SQLite ist Laravels Standard. Wann reicht das?
Der Standard hat sich geändert, und viele Anwendungen gingen damit in Produktion, ohne dass jemand es entschieden hätte. Die Fälle, in denen das richtig ist, sind enger als gedacht.
Laravels Standarddatenbank ist SQLite, und Standards sind mächtig. Eine nennenswerte Zahl von Anwendungen erreicht die Produktion heute darauf, weil niemand die Zeile geändert hat, nicht weil jemand entschieden hätte, dass es passt.
Manchmal passt es. Hier verläuft die Linie tatsächlich.
Was wirklich anders ist
Nicht das SQL. Nicht Eloquent, das sich gleich verhält. Eine Sache: SQLite ist eine Datei, die Ihr Prozess öffnet, kein Server, zu dem er sich verbindet.
Alles folgt daraus. Es gibt kein Verbindungslimit, weil es keine Verbindungen gibt. Es gibt keine Netzwerklatenz, weil es kein Netzwerk gibt. Und Schreibzugriffe werden über jeden Prozess serialisiert, der die Datei anfasst, weil eine Datei keinen Planer hat, der zwischen Clients vermittelt.
Schalten Sie WAL ein, bevor Sie sonst etwas tun. Ohne WAL blockiert ein Leser einen Schreiber und ein Schreiber die Leser, und das ist die Konfiguration, die die meisten Leute messen, ohne es zu wissen:
// eine Migration, oder ein Service Provider
DB::statement('PRAGMA journal_mode = WAL');
DB::statement('PRAGMA busy_timeout = 5000');
DB::statement('PRAGMA foreign_keys = ON');Diese drei sind nahezu Pflicht. WAL lässt Leser während eines Schreibvorgangs
weiterarbeiten. Der Busy-Timeout verwandelt einen sofortigen database is locked-Fehler in eine kurze Wartezeit, was fast immer gewollt war. Und
Fremdschlüssel sind in SQLite standardmäßig aus, was Leute überrascht, die
constrained() in eine Migration geschrieben und angenommen haben, es werde
durchgesetzt.
Wo es die richtige Antwort ist
Ein internes Werkzeug. Zwanzig Personen, überwiegend lesend. Die betriebliche Ersparnis ist real: kein Datenbankserver zu patchen, zu sichern, abzusichern oder zu bezahlen, und ein Backup ist eine Dateikopie.
Eine Ein-Server-Anwendung mit moderaten Schreibzugriffen. Eine Inhaltsseite, eine Buchungsseite, ein kleines SaaS im ersten Jahr. SQLite auf lokaler Platte ist für einen einzelnen Leser schneller als Postgres über Netzwerk, weil kein Socket überquert wird.
Tests. Eine In-Memory-SQLite-Datenbank macht eine Suite schnell, mit dem Vorbehalt unten.
Alles Eingebettete oder am Rand Ausgelieferte, wo ein Datenbankserver überhaupt nicht zur Verfügung steht.
Wo es das nicht ist
Mehrere Anwendungsserver. Das ist die harte Grenze. Zwei Webserver können eine SQLite-Datei über ein Netzwerkdateisystem nicht sicher teilen. Wenn Sie je horizontal skalieren, muss diese Entscheidung erneut getroffen werden, und sie später zu treffen heißt Migration unter Zeitdruck.
Schreiblastige Arbeit. Alles, was jede Anfrage protokolliert, Ereignisse aufnimmt oder eine Queue in der Datenbank verarbeitet. Schreibzugriffe serialisieren; das ist der Entwurf, kein Tuning-Problem.
Mehr als ein, zwei Queue-Worker. Worker, die eine Jobs-Tabelle abfragen, sind gleichzeitige Schreiber. Nehmen Sie Redis für die Queue und SQLite für die Anwendung, oder betreiben Sie einen Worker und akzeptieren Sie den Durchsatz.
Alles, was Point-in-Time-Recovery braucht, Replikation oder eine Lese-Replik. Es gibt Werkzeuge, die Replikation auf SQLite aufsetzen, und die sind eine Abhängigkeit und eine Entscheidung, kein Standard.
Die Testfalle
Die häufigste SQLite-Entscheidung in einer Laravel-Codebasis ist nicht die in
Produktion. Es ist :memory: in phpunit.xml, wegen der Geschwindigkeit
gewählt, gegen eine Anwendung, die MySQL oder Postgres betreibt.
Diese Suite kann nicht fangen:
- Eine Constraint-Verletzung, die die echte Engine durchsetzt und SQLite nicht.
- Einen Kollationsunterschied, also die Groß-/Kleinschreibungsfalle mit anderem Hut.
- Eine Migration, die eine große Tabelle sperrt, weil es weder Sperre noch Tabelle gibt.
- Alles mit einem JSON-Operator, einer Fensterfunktion oder einem Typ, den die echte Engine hat und SQLite nicht.
Für eine unit-lastige Suite ist das ein vernünftiger Tausch und als einziges Bollwerk gegen einen Schemafehler ein schlechter. Lassen Sie die schnelle Suite auf SQLite laufen, wenn Sie mögen; lassen Sie die Suite, die ein Deployment freigibt, gegen die Engine laufen, auf die Sie deployen.
Ehrlich entscheiden
Stellen Sie eine Frage: wird diese Anwendung je auf mehr als einem Server laufen?
Ist die Antwort nein und wissen Sie warum - sie ist intern, sie hat eine Obergrenze, sie ist tatsächlich klein - dann ist SQLite kein Kompromiss. Es ist weniger Infrastruktur, die Ihnen gehört, und weniger Infrastruktur zu besitzen ist ein echter Vorteil, der zu leicht abgetan wird.
Ist die Antwort ja, oder "wahrscheinlich nicht, aber wer weiß", beginnen Sie auf der Engine, auf der Sie enden würden. Eine laufende Anwendung zu migrieren ist Arbeit, die Sie ganz vermeiden, indem Sie in Woche eins zehn Minuten darauf verwenden - dasselbe Argument wie bei Geld und Zeit, und es gilt aus demselben Grund.
