Menu

SQLite In-Memory: Datenbanken im RAM mit :memory:

Wie die In-Memory-Datenbank von SQLite funktioniert, wann :memory: wirklich Sinn ergibt und worin der Unterschied zu einer dateibasierten Datenbank liegt.

Diese Seite enthält ausführbare Editoren — bearbeiten, ausführen und Ausgabe sofort sehen.

Eine Datenbank, die im RAM lebt

SQLite kennt einen besonderen Dateinamen: :memory:. Öffnest du eine Datenbank mit diesem Namen, lässt SQLite die Festplatte komplett links liegen – die gesamte SQLite In-Memory-Datenbank liegt im RAM. Tabellen, Indizes, Transaktionen, Foreign Keys: alle Features funktionieren genau gleich. Der einzige Unterschied: Sobald die Verbindung geschlossen wird, ist die Datenbank weg.

Auf der Kommandozeile:

sqlite3 :memory:

Du sitzt jetzt am SQLite-Prompt mit einer frischen, leeren In-Memory-Datenbank, die ausschließlich im RAM lebt. Leg eine Tabelle an, füg ein paar Zeilen ein, frag sie ab – alles ganz normal:

Sobald du die Session beendest, ist diese Datenbank weg. Es bleibt keine Datei zurück, denn es wurde nie eine angelegt.

Wofür ist eine SQLite In-Memory-Datenbank gut?

Eine Datenbank, die einen Neustart nicht überlebt, klingt erstmal nach einem Bug, nicht nach einem Feature. Trotzdem ist sie in drei Szenarien richtig praktisch.

Tests. Jeder Test bekommt in Millisekunden eine frische Datenbank. Kein Aufräumen von Tempfiles, kein übriggebliebener Zustand aus dem letzten Lauf, keine geteilte Fixture-Datei, die plötzlich gesperrt ist. Genau deshalb öffnen die meisten Python-, Node- und Go-Testsuites mit SQLite einfach :memory:.

Wegwerf-Analysen. CSV laden, ein paar Queries draufjagen, wegschmeißen. Schneller als eine richtige Datenbank hochzuziehen und bequemer, als die Datei jedes Mal im Code zu parsen.

Caching und Scratch-Space. In einem länger laufenden Programm ist eine SQLite In-Memory-Datenbank eine überraschend gute Ad-hoc-Query-Engine für Daten, die du sowieso schon im Speicher hast.

Der gemeinsame Nenner: Du willst SQL, aber keine Persistenz.

Performance: schneller, aber kein Wundermittel

In-Memory-Datenbanken umgehen die Platte komplett — Schreibvorgänge, die sonst aufs Dateisystem gehen würden, sind hier schlicht Speicherzugriffe. I/O-lastige Workloads werden dadurch spürbar schneller. CPU-lastige Workloads dagegen — komplexe Query-Planung, große Sortierungen — gewinnen kaum etwas, weil SQLite häufig benutzte Pages ohnehin schon im RAM cached.

Eine kurze Demo, wie identisch die Syntax bleibt:

Das lief gerade gegen eine In-Memory-Datenbank, aber es ist exakt dasselbe SQL, das du auch gegen eine Datei ausführen würdest. Der Datenbank-Engine ist das egal.

SQLite In Memory vs. Datei: Wann nimmst du was?

Die Abwägung ist eigentlich ganz einfach, aber sie sollte trotzdem klar auf dem Tisch liegen:

  • Datei-Datenbank (mydata.db): Bleibt über Neustarts hinweg erhalten. Mehrere Prozesse können sie gleichzeitig öffnen. Übersteht Abstürze (mit WAL-Modus zumindest weitgehend). Nimm das, sobald sich irgendetwas dauerhaft merken soll.
  • In-Memory-Datenbank (:memory:): Ist nach dem Schließen weg. Standardmäßig nur für die Verbindung sichtbar, die sie geöffnet hat. Schneller bei schreibintensiver Wegwerf-Arbeit. Ideal für Tests, schnelle Experimente und kurzlebige Caches.

Im Zweifel willst du eine Datei. In-Memory ist der Spezialfall.

Jede Verbindung bekommt ihre eigene Datenbank

Eine Kleinigkeit, über die viele stolpern: Wenn du :memory: zweimal öffnest, bekommst du zwei komplett getrennte Datenbanken. Keine gemeinsamen Tabellen, keine gemeinsamen Daten – sie wissen nicht einmal voneinander.

-- Terminal 1
sqlite3 :memory:
sqlite> CREATE TABLE t (x); INSERT INTO t VALUES (1);

-- Terminal 2
sqlite3 :memory:
sqlite> SELECT * FROM t;
Error: no such table: t

Das ist kein Bug, sondern Absicht: :memory: bedeutet "eine private Datenbank für diese Verbindung". Das gilt auch innerhalb eines einzelnen Programms – öffnet dein Code zwei Verbindungen zu :memory:, bekommt jede ihre eigene, isolierte Datenbank.

SQLite Shared Cache In-Memory: Datenbank über Verbindungen hinweg teilen

Wenn mehrere Verbindungen tatsächlich auf dieselbe In-Memory-Datenbank zugreifen sollen, geht das in SQLite über URI-Dateinamen und den Shared Cache. Der entscheidende String dafür ist file::memory:?cache=shared:

sqlite3 'file::memory:?cache=shared'

Jede Verbindung im selben Prozess, die genau diese URI öffnet, landet in derselben Datenbank. Sobald alle geschlossen sind, ist die Datenbank weg.

Du kannst der In-Memory-Datenbank auch einen Namen geben – praktisch, wenn du mehrere voneinander getrennte Shared-Datenbanken parallel betreiben willst:

sqlite3 'file:mydb?mode=memory&cache=shared'

Der Name mydb ist hier nur ein Label – eine Datei entsteht dadurch immer noch nicht. Zwei Verbindungen, die file:mydb?mode=memory&cache=shared öffnen, greifen auf dieselbe Datenbank zu; eine Verbindung mit file:other?mode=memory&cache=shared landet dagegen in einer anderen.

SQLite In-Memory-Datenbank auf Festplatte speichern

Manchmal läuft der komplette Workflow im RAM ab, und am Ende möchtest du das Ergebnis dann doch behalten. Genau dafür bietet die CLI den Punkt-Befehl .backup:

sqlite3 :memory:
sqlite> CREATE TABLE results (id INTEGER, score REAL);
sqlite> INSERT INTO results VALUES (1, 0.91), (2, 0.87);
sqlite> .backup snapshot.db
sqlite> .quit

snapshot.db ist jetzt eine ganz normale Datei-Datenbank mit demselben Inhalt. Du kannst sie später einfach mit sqlite3 snapshot.db öffnen und genau dort weitermachen, wo du aufgehört hast.

Andersrum geht's natürlich auch — mit .restore lädst du eine Datei-Datenbank in den Speicher der aktuellen Verbindung:

sqlite3 :memory:
sqlite> .restore snapshot.db
sqlite> SELECT * FROM results;

Aus Anwendungscode heraus stellt die SQLite-C-API dieselben Mechanismen wie sqlite3_backup_init bereit, und die meisten Sprachbindings haben dafür einen Wrapper. Pythons sqlite3-Modul bietet beispielsweise Connection.backup().

Ein häufiger Stolperstein

Immer wieder versuchen Leute, eine In-Memory-Datenbank zu „sichern", indem sie eine Datei anhängen und einfach umkopieren:

Das funktioniert für einfache Tabellenkopien, bewahrt aber Indizes, Trigger, Views oder Fremdschlüssel nicht exakt so, wie sie waren. Wenn du eine komplette Datenbank originalgetreu kopieren willst, nimm .backup (oder die Backup-API) — das erzeugt eine binär-exakte Kopie auf Seitenebene.

Was du mitnimmst

  • :memory: ist ein spezieller SQLite-Dateiname, der eine Datenbank im RAM anlegt, ganz ohne Datei dahinter.
  • Das SQL ist identisch zur dateibasierten Variante — gleiche Tabellen, gleiche Queries, gleiche Constraints.
  • Jede Verbindung zu :memory: ist privat; nutze Shared-Cache-URIs (file::memory:?cache=shared), wenn sich mehrere Verbindungen eine Datenbank teilen sollen.
  • Ideal für Tests, kurzlebige Analysen und temporäre Caches — nichts, was einen Neustart überleben muss.
  • Mit .backup lässt sich eine In-Memory-Datenbank auf die Festplatte sichern, sobald du sie doch behalten willst.

Weiter: Tabellen anlegen

In den bisherigen Beispielen ist CREATE TABLE schon ein paarmal kurz aufgetaucht. Auf der nächsten Seite gehen wir es in Ruhe durch — Spaltendefinitionen, Typen, die Constraints, die du anhängen kannst, und die kleinen Entscheidungen, die ein Schema im Alltag angenehm machen.

Häufig gestellte Fragen

Wie legt man eine In-Memory-Datenbank in SQLite an?

Statt eines Dateipfads gibst du beim Öffnen einfach den speziellen Namen :memory: an. Auf der Kommandozeile sieht das so aus: sqlite3 :memory:. In einer Library nutzt du den entsprechenden connect-Aufruf und übergibst :memory: als Dateinamen. Die Datenbank lebt komplett im RAM und ist weg, sobald die Verbindung geschlossen wird.

Was bedeutet :memory: in SQLite?

:memory: ist ein magischer Dateiname, den SQLite als „keine Datei nutzen, alles im RAM halten" interpretiert. Du bekommst trotzdem eine vollwertige SQLite-Datenbank — mit Tabellen, Indexen, Transaktionen, allem drum und dran — aber nichts landet jemals auf der Platte. Jede Verbindung, die :memory: öffnet, bekommt ihre eigene, private Datenbank.

Können sich zwei Connections eine In-Memory-Datenbank teilen?

Standardmäßig nicht — jede :memory:-Verbindung ist isoliert. Wenn du sie teilen willst, öffne sie über eine URI wie file::memory:?cache=shared und aktiviere den Shared Cache. Alle Verbindungen, die innerhalb desselben Prozesses exakt diese URI öffnen, sehen dieselbe Datenbank.

Kann man eine In-Memory-Datenbank auf die Festplatte speichern?

Ja. Mit dem .backup-Befehl in der CLI oder über die Backup-API deiner Library kannst du die In-Memory-Datenbank in eine Datei kopieren. Alternativ funktioniert auch ATTACH einer Datei-Datenbank plus INSERT INTO file.table SELECT * FROM main.table, um die Daten rüberzuziehen.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S