LimeSurvey und wie Antworten gespeichert werden

112233X12X42

Die Art, wie LimeSurvey Umfrageantworten speichert, gehört zu den ältesten und fundamentalsten Architekturentscheidungen der Plattform. Sie beeinflusst alles, was darüber liegt: Plugins, Integrationen, Reporting und die Erweiterbarkeit des Systems.

Wer mit LimeSurvey arbeitet, kommt früher oder später mit dieser Struktur in Berührung – spätestens dann, wenn Antwortdaten außerhalb der Plattform ausgewertet oder in eigene Systeme integriert werden sollen.


Survey-spezifische Antworttabellen

Für jede Umfrage legt LimeSurvey eine eigene Datenbanktabelle an. Der Tabellenname folgt dem Schema

survey_<sid>

wobei <sid> der Survey-ID entspricht – zum Beispiel:

survey_112233

Alle Antworten aller Teilnehmer dieser Umfrage werden in dieser einen Tabelle gespeichert.

Das war zu seiner Zeit eine pragmatische Entscheidung. Eine Tabelle pro Umfrage ist leicht zu verstehen, einfach zu debuggen und erlaubt schnelle Abfragen ohne komplexe Joins. Für kleine bis mittelgroße Umfragen funktioniert dieses Modell zuverlässig und performant.

Datenbankseitig entspricht dieses Modell einem Wide-Table-Design: Jede Frage – oder sogar jede Teilfrage – wird zu einer eigenen Spalte. Die Antworten eines Teilnehmers bilden eine einzelne Zeile, die alle Antworten enthält.

Die Kehrseite zeigt sich, sobald man über eine einzelne Umfrage hinausdenkt. Wer mehrere Umfragen zusammenführen, vergleichen oder in ein Data Warehouse überführen möchte, arbeitet nicht mit einer einheitlichen Struktur, sondern mit einer Vielzahl unterschiedlicher Tabellen.


Warum dieses Modell damals sinnvoll war

Aus heutiger Sicht wirkt dieses Wide-Table-Design ungewöhnlich. In der Zeit, in der LimeSurvey entstand, war es jedoch eine sehr pragmatische Entscheidung.

Frühe Web-Stacks bestanden typischerweise aus PHP und MySQL-Versionen, deren Query-Optimizer bei komplexen Joins deutlich schwächer war als heute. Abfragen über viele Tabellen konnten schnell zum Performanceproblem werden.

Das Wide-Table-Modell vermeidet dieses Problem vollständig: Jede Antwort eines Teilnehmers liegt in genau einer Zeile, und viele Auswertungen können ohne Joins erfolgen.

Auch für Datenexporte ist dieses Modell ideal. CSV- oder SPSS-Dateien lassen sich direkt erzeugen, da jede Zeile einem Teilnehmer und jede Spalte einer Frage entspricht.

Für die technischen Rahmenbedingungen der damaligen Zeit war dieses Modell daher nicht nur einfach – sondern auch effizient.


Das Feldnamenschema (SGQA)

Die Spaltennamen innerhalb der Antworttabellen folgen einem internen Schema, das als SGQA bekannt ist:

Die Komponenten werden durch X getrennt.

Grundschema:

sidXgidXqid

Beispiel:

112233X12X42

Bei Fragetypen mit Teilfragen oder Antwortoptionen wird ein zusätzlicher Suffix angehängt.

Fragetyp Code Feldname-Schema Beispiel
Radio List L sidXgidXqid 112233X12X42
Radio List (Other) L sidXgidXqidother 112233X12X42other
Multiple Choice M sidXgidXqid + aid 112233X12X42SQ001
Multiple Choice mit Kommentar P sidXgidXqid + aid 112233X12X42SQ001
Kommentar-Feld P sidXgidXqid + aid + comment 112233X12X42SQ001comment
Array F sidXgidXqid + aid 112233X12X42SQ001
Array Dual Scale 1 sidXgidXqid + aid + #scale 112233X12X42SQ001#0

Die aid entspricht dem Code der Teilfrage oder Antwortoption. Standardmäßig erzeugt LimeSurvey Codes wie:

SQ001
SQ002
SQ003

Das Schema ist intern konsistent, aber ohne Kenntnis der Struktur schwer zu lesen.


Eine kleine historische Kuriosität

Auf den ersten Blick enthält SGQA eine Redundanz: Die Survey-ID (sid) steht sowohl im Tabellennamen als auch im Feldnamen.

Wenn die Tabelle bereits survey_112233 heißt – warum dann noch einmal 112233 im Feldnamen?

Der Grund liegt in der ursprünglichen Architektur des Expression-Systems. SGQA diente dort als globale Referenz für Fragen, zum Beispiel in Relevanzbedingungen oder Validierungsregeln:

{112233X12X42 == "Y"}

Damit konnte das System jede Frage eindeutig identifizieren – unabhängig davon, in welcher Umfrage oder Gruppe sie gerade verarbeitet wurde.

Heute wirkt diese Redundanz ungewohnt, erklärt aber, warum das Schema so lange unverändert geblieben ist.


Datentypen der Antwortspalten

Die tatsächlichen Datentypen der Antwortfelder sind meist relativ klein. Typische Beispiele sind:

Fragetyp Datentyp Inhalt
Single Choice VARCHAR(5) Antwortcode
Matrix / Array VARCHAR(5) Antwortcode
Multiple Choice VARCHAR(1) 'Y' oder NULL
Textfragen TEXT Freitext
Numerische Fragen DECIMAL(30,10) numerischer Wert

Viele Spalten sind damit sehr kompakt. Eine typische Single-Choice-Antwort benötigt zum Beispiel nur wenige Bytes, da lediglich der Antwortcode gespeichert wird.

Die Herausforderung liegt daher meist nicht in der Größe einzelner Spalten, sondern in der Anzahl der Spalten, die große Umfragen erzeugen können.


Die MySQL-Zeilengrößen-Limitierung

MySQL begrenzt die maximale Zeilengröße auf 65.535 Bytes.

Da LimeSurvey alle Antworten eines Teilnehmers in einer einzigen Zeile speichert, wächst die Zeilengröße mit jeder zusätzlichen Frage oder Teilfrage.

Dabei ist wichtig: MySQL berechnet die Zeilengröße nicht aus den tatsächlich gespeicherten Daten, sondern aus der maximal möglichen Länge jeder Spalte.

Eine Spalte

VARCHAR(5) utf8mb4

kann bis zu

5 × 4 = 20 Bytes

belegen, da utf8mb4 bis zu vier Bytes pro Zeichen verwendet.

Die effektive Zeilengröße ergibt sich aus der Summe der maximal möglichen Speicherbedarfe aller Spalten.

Große Umfragen mit vielen Matrixfragen oder umfangreichen Multiple-Choice-Blöcken können dadurch sehr breite Tabellen erzeugen. Wird die maximale Zeilengröße überschritten, verweigert MySQL die Erstellung der Tabelle mit dem Fehler:

Row size too large

Die Umfrage lässt sich dann nicht aktivieren.

In der Praxis kann neben der Zeilengröße auch ein weiteres MySQL-Limit relevant werden: Tabellen dürfen maximal rund 1000 Spalten enthalten.


Konsequenzen für Plugins und Integrationen

Wer Plugins oder externe Integrationen entwickelt, die direkt auf Antworttabellen zugreifen, muss das SGQA-Schema korrekt berücksichtigen.

Änderungen an Fragen oder Gruppen können Feldnamen beeinflussen. Integrationen, die Feldnamen hart kodieren, sind daher fragil.

LimeSurvey stellt mit createFieldMap() eine Hilfsfunktion bereit, die das aktuelle Feldnamenschema einer Umfrage liefert. Diese Funktion sollte bevorzugt verwendet werden.


Ein moderner Alternativansatz

Würde man das Speichermodell heute neu entwerfen, kämen verschiedene alternative Ansätze infrage.

Eine mögliche Variante wäre ein Modell, bei dem jede Frage einer Spalte entspricht und die eigentlichen Antwortdaten als JSON gespeichert werden.

response_id Q1 Q2 Q3
1 {"value":"A1"} {"value":"Ja"} {"value":42}
2 {"SQ001":"A2","SQ002":"A1"} {"value":"Nein"} {"value":7}

Der Spaltenname entspricht dem Fragecode und ist damit stabil und menschenlesbar.

Das JSON enthält die eigentlichen Antwortdaten – bei einfachen Fragen ein einzelner Wert, bei komplexeren Fragen strukturierte Informationen.

Ein solcher Ansatz reduziert strukturelle Einschränkungen erheblich. TEXT- oder JSON-Spalten zählen in MySQL nur mit wenigen Bytes zur Zeilengröße, sodass die 65-KB-Grenze praktisch keine Rolle mehr spielt.

Der Preis ist jedoch real: Abfragen auf Teilfragenebene erfordern JSON-Extraktion, bestehende Reporting-Tools müssten angepasst werden, und eine Migration vorhandener Daten wäre aufwendig. Was das strukturell bedeutet, haben wir im Artikel Der Rewrite-Reflex ausführlicher beleuchtet.


Wide Tables sind nicht grundsätzlich ein Problem

Ein Wide-Table-Design ist nicht grundsätzlich falsch. In vielen analytischen Szenarien ist es sogar vorteilhaft.

Data-Warehouse-Systeme und analytische Datenbanken arbeiten häufig mit sehr breiten Tabellen, weil viele Abfragen spaltenweise erfolgen. Moderne spaltenorientierte Systeme wie ClickHouse oder BigQuery sind explizit für solche Strukturen optimiert.

Auch in LimeSurvey hat dieses Modell Vorteile: Ein kompletter Datensatz eines Teilnehmers lässt sich sehr einfach exportieren oder analysieren.

Die Herausforderungen entstehen vor allem dann, wenn sehr große Umfragen erstellt werden oder externe Systeme flexibel auf einzelne Fragen zugreifen müssen.


Ausblick: LimeSurvey 7

LimeSurvey adressiert in Version 7 Beta 1 genau diese Punkte. Die Änderungen sind struktureller Natur – keine neuen Features, aber eine grundlegende Bereinigung:

Das ist eine direkte Antwort auf die Schwächen des bisherigen Modells: mehr Lesbarkeit, mehr Konsistenz, eine stabilere Basis für Plugins und Integrationen. Wer eigene Plugins, Themes oder Integrationen betreibt, sollte die Beta im Blick behalten – Anpassungen werden nötig sein.

Wir werden auf Version 7 und die Konsequenzen dieser Änderungen zurückkommen, sobald die finale Version verfügbar ist.


Fazit

Das Speichermodell von LimeSurvey ist ein gutes Beispiel für historisch gewachsene Architekturentscheidungen: pragmatisch und effizient in ihrer Zeit, mit Konsequenzen, die erst sichtbar werden, wenn Systeme über ihre ursprünglichen Anforderungen hinaus genutzt werden.

Dass LimeSurvey diese Struktur in Version 7 selbst überarbeitet, zeigt, dass der Modernisierungsbedarf erkannt wurde – und dass selbst grundlegende Architekturentscheidungen nicht für immer unveränderlich sind.