Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 6 Min.

SQLite als Dokumentenspeicher: Kann das gut gehen?

Die Embedded SQL-Datenbank SQLite kann auch als objektorientierte Datenbank beziehungsweise Dokumentenspeicher genutzt werden – nach Konzepten also, wie sie NoSQL-Datenbanken wie MongoDB einsetzen.
© EMGenie

In den ersten vier Teilen dieser Serie haben wir SQLite als leistungsfähige Embedded-Datenbank, als .NET-Integrationskünstler, als Basis für verteilte Systeme und als leistungsfähige Volltextsuchmaschine mit FTS5 kennengelernt. Im fünften und letzten Teil wagen wir ein Experiment: Was passiert, wenn man SQLite nicht als klassische relationale Datenbank nutzt, sondern als Dokumentenspeicher? Mit JSON-Spalten und Generated Columns lässt sich ein hybrides Datenmodell aufbauen, das erstaunlich nah an MongoDB herankommt – ohne dessen operativen Overhead.

JSON als Dokument: das Grundprinzip

Die Idee ist einfach: Statt ein starres relationales Schema zu definieren, speichert man Dokumente als JSON in einer TEXT-Spalte. SQLite validiert das JSON beim Einfügen, und die eingebauten JSON-Funktionen ermöglichen den Zugriff auf einzelne Felder direkt in SQL. Das ist kein Hack, sondern ein offiziell unterstütztes Feature, das seit SQLite 3.38 sogar eine eigene Kurzschreibweise hat: den ->>-Operator, den man von PostgreSQL kennt.

Die JSON-Unterstützung in SQLite geht dabei weit über einfaches Lesen und Schreiben hinaus. Mit json_extract greift man auf verschachtelte Felder zu, json_each iteriert über Arrays innerhalb eines Dokuments, und json_patch ermöglicht partielle Updates, ähnlich wie mit dem $set-Operator von MongoDB. Seit Version 3.45 gibt es zusätzlich json_tree, das den gesamten Dokumentenbaum traversiert und damit auch tief verschachtelte Strukturen durchsuchbar macht. Wer mit XPath oder JSONPath vertraut ist, findet sich schnell zurecht.

Ein minimales Dokumentenmodell besteht aus einer Tabelle mit einer ID und einer JSON-Spalte. Die Tabellendefinition zeigt, wie schlank der Ansatz ist:

 

CREATE TABLE documents (
  id TEXT PRIMARY KEY,
  type TEXT NOT NULL,
  data TEXT NOT NULL CHECK(json_valid(data)),
  created_at TEXT DEFAULT(datetime()),
  -- Generated Columns für Indizierung
  name GENERATED ALWAYS AS
    (json_extract(data, '$.name')) STORED
);

 

Die CHECK-Constraint mit json_valid stellt sicher, dass nur gültiges JSON eingefügt wird, ähnlich wie MongoDB invalides BSON ablehnt. Die Generated Column extrahiert den Namen aus dem JSON und speichert ihn als echte Spalte, die sich indizieren lässt. Das ist der entscheidende Trick: Man behält die Flexibilität eines schemafreien Dokumentenmodells, kann aber häufig abgefragte Felder wie klassische Spalten behandeln.

In der Praxis bedeutet das: Ein INSERT mit einem JSON-Objekt reicht aus, um ein neues Dokument anzulegen. Abfragen auf verschachtelte Felder funktionieren mit der ->>-Syntax so intuitiv wie in MongoDB. Ein SELECT data ->> '$.address.city' FROM documents liefert direkt den Wert aus dem verschachtelten Objekt. Will man alle Dokumente finden, die ein bestimmtes Tag in einem Array enthalten, kombiniert man json_each mit einer WHERE-Klausel – ein Pattern, das MongoDB-Entwickler als $elemMatch kennen.

Der Vergleich mit MongoDB

Wer mit MongoDB gearbeitet hat, erkennt die Parallelen sofort: schemalose Dokumente, flexible Strukturen, Queries auf verschachtelte Felder. Aber die Unterschiede sind ebenso aufschlussreich. MongoDB ist eine verteilte Datenbank mit eingebautem Sharding, Replica Sets und einer eigenen Query-Sprache. SQLite mit JSON-Spalten ist eine einzelne Datei mit SQL. Die Entscheidung zwischen beiden hängt nicht davon ab, welche Technologie besser ist, sondern welches Profil die Anwendung hat.

Für Anwendungen mit moderatem Datenvolumen auf einem einzelnen Server ist SQLite als Dokumentenspeicher oft eine mögliche und pragmatische Wahl. Kein MongoDB-Server, der gewartet werden muss. Keine WiredTiger-Storage-Engine, deren Konfiguration man verstehen muss. Kein Replica Set, das bei Netzwerkpartitionen in einen Read-only-Zustand fällt. Stattdessen: Eine Datei, SQL-Queries und ACID-Transaktionen, die einfach funktionieren. Andererseits ist die Performance, die eine MongoDB (auch in der Community Edition) hervorbringt, meilenweit einer SQLite überlegen.

Ein Aspekt, den man kennen sollte: MongoDB steht seit 2018 unter der SSPL-Lizenz. Die SSPL-Copyleft-Bedingung greift allerdings nur, wenn man MongoDB selbst als Dienst anbietet – also ein Database-as-a-Service-Produkt, wie MongoDB Atlas nachbaut und Endkunden direkten Datenbankzugang gibt. Wer MongoDB lediglich als Backend für eine eigene Anwendung nutzt, ist nicht betroffen. Dennoch führt die SSPL in vielen Unternehmen zu Compliance-Diskussionen und rechtlicher Prüfung. SQLite hingegen ist Public Domain – keine Lizenzfragen, keine Compliance-Risiken, keine Überraschungen bei einem Audit. Für Start-ups und ISVs, die jede rechtliche Grauzone vermeiden wollen, ist das ein handfester Vorteil.

Das Hybridmodell: Relational trifft dokumentenorientiert

Die eigentliche Stärke von SQLite als Dokumentenspeicher liegt im Hybridmodell. Anders als MongoDB, das rein dokumentenorientiert ist, kann man in SQLite relationale und dokumentenorientierte Ansätze frei mischen. Stammdaten wie Benutzer oder Konfigurationen liegen in klassischen Tabellen mit festem Schema. Flexible Daten wie Formulareingaben, Event-Payloads oder API-Responses werden als JSON gespeichert. Beides lebt in derselben Datenbank und lässt sich in einer einzigen Query joinen.

Dieses Muster ist besonders wertvoll, wenn sich das Datenmodell während der Entwicklung noch verändert. Statt bei jeder Änderung eine Migration schreiben zu müssen, packt man die sich ändernden Felder ins JSON und extrahiert sie erst dann als Generated Columns, wenn das Schema stabil ist. Das spart Entwicklungszeit, ohne die Query-Performance zu opfern, denn die Generated Columns sind genauso schnell wie klassische Spalten.

Ein konkretes Beispiel verdeutlicht den Vorteil: Eine E-Commerce-Anwendung speichert Bestellungen als JSON-Dokumente, weil jede Produktkategorie unterschiedliche Attribute mitbringt. Ein T-Shirt hat Größe und Farbe, ein Laptop hat RAM und Bildschirmdiagonale. In einem rein relationalen Modell bräuchte man etwas wie eine Entity-Attribute-Value-Tabelle oder Dutzende Nullable-Spalten. Mit JSON-Spalten speichert man einfach das gesamte Produkt als Dokument und legt Generated Columns nur für die Felder an, nach denen tatsächlich gefiltert oder sortiert wird. Im konkreten Fall bedeutet das: Die Produkte einer Bestellung sind JSON-Arrays innerhalb des Bestellungsdokuments. Eine Aggregation über alle Bestellungen könnte dann mit json_each alle Produkte entpacken, diese dann mit einer Kategorie-Referenztabelle joinen und schließlich Umsätze pro Kategorie berechnen, das Ganze mit einem INDEX auf die extrahierte Kategorie-ID als Generated Column. So erreicht man Performance und Flexibilität in Einklang.

Damit dieses Modell robust bleibt, sollte man die Konsistenz der JSON-Dokumente nicht dem Anwendungscode überlassen. Die JSON-Funktionen von SQLite bieten die Möglichkeit, mit Constraints zu validieren, nicht auf Schema-Ebene wie in MongoDB, aber durch CHECK-Constraints, die JSON-Strukturen prüfen. json_schema kann zum Beispiel überprüfen, ob bestimmte Felder vorhanden sind oder einen definierten Datentyp haben. json_patch ermöglicht partielle Updates, ohne dass man das gesamte Dokument neu schreiben muss, ähnlich wie der $set-Operator in MongoDB, aber stärker typsicher, weil man SQL-Expressions verwendet.

Die Kombination aus JSON-Funktionen und SQL-Aggregation öffnet elegante Wege zur Auswertung. Mit Common Table Expressions und Window Functions lassen sich MongoDB-ähnliche Aggregation Pipelines in reines SQL übersetzen. Ein WITH-Block extrahiert die relevanten Felder, eine OVER-Clause berechnet Rankings oder laufende Summen, und das Ergebnis ist ein sauberer Report – alles in einer einzigen Query, ohne zusätzlichen Application-Code. Für Reports über Bestellungen, Kategorien und Mengen ist das deutlich effizienter als Application-seitiges Grouping.

Fazit: SQLite ist keine Kompromisslösung

Über fünf Artikel hinweg haben wir SQLite aus verschiedenen Perspektiven betrachtet: als performante Embedded-Datenbank mit überraschenden Benchmarks, als nahtlos integrierte .NET-Komponente, als Basis für verteilte Systeme mit libSQL und Turso, als leistungsfähige Volltextsuchmaschine mit FTS5, und nun als flexiblen Dokumentenspeicher. Die durchgängige Erkenntnis: SQLite ist keine Kompromisslösung für Prototypen, sondern für eine wachsende Zahl von Szenarien die architektonisch bessere Wahl.

Der Rat an .NET-Entwickler, die beim nächsten Projekt reflexartig zu SQL Server oder PostgreSQL greifen: Haltet kurz inne und fragt euch, ob die Anwendung wirklich einen separaten Datenbankserver braucht. Wenn die Antwort nicht eindeutig Ja lautet, gebt SQLite eine Chance. Die Datenbank, die in Milliarden von Geräten ihren Dienst tut, hat sich längst von der Spielzeug-Datenbank zur ernsthaften Alternative entwickelt. Manchmal ist weniger tatsächlich mehr und eine einzige Datei genug.

Neueste Beiträge

libSQL und Turso: SQLite für verteilte Systeme - SQLite für .NET-Entwickler, Teil 3
libSQL und Turso lösen die größte Einschränkung von SQLite: die Bindung an eine einzelne Instanz.
6 Minuten
15. Apr 2026
Maschinelles Lernen in .NET - .NET, Python und KI, Teil 2
Für eine performante und plattformübergreifende Inferenz von NET-Projekten empfiehlt sich eine hybride Strategie aus Training oder Prototyping in Scikit-Learn/Python, Export nach ONNX und Einbindung in .NET über ML.NET oder ONNX Runtime.
7 Minuten
Volltextsuche mit SQLite: FTS5 und Fuzzy Search - SQLite für .NET-Entwickler, Teil 4
Hochperformante Suche ohne externe Suchmaschine? Wie man mit der in SQLite eingebauten Volltextsuch-Engine FTS5 eine effiziente Suche mit Tippfehlertoleranz implementiert – und in welchen Fällen Elasticsearch doch die bessere Wahl ist.
6 Minuten
22. Apr 2026

Das könnte Dich auch interessieren

SQLite: Wenn weniger mehr ist - SQLite für .NET-Entwickler, Teil 1
Für Entwicklerteams, die jeden Tag mit der Komplexität von Kubernetes, Cloud-Datenbanken und Terraform-Skripten ringen, liegt der eigentliche Gewinn von SQLite in der architektonischen Vereinfachung.
6 Minuten
Volltextsuche mit SQLite: FTS5 und Fuzzy Search - SQLite für .NET-Entwickler, Teil 4
Hochperformante Suche ohne externe Suchmaschine? Wie man mit der in SQLite eingebauten Volltextsuch-Engine FTS5 eine effiziente Suche mit Tippfehlertoleranz implementiert – und in welchen Fällen Elasticsearch doch die bessere Wahl ist.
6 Minuten
22. Apr 2026
libSQL und Turso: SQLite für verteilte Systeme - SQLite für .NET-Entwickler, Teil 3
libSQL und Turso lösen die größte Einschränkung von SQLite: die Bindung an eine einzelne Instanz.
6 Minuten
15. Apr 2026
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige