Behandelt SQLite3 den gleichzeitigen Zugriff durch mehrere Prozesse, die aus derselben Datenbank lesen / schreiben, sicher? Gibt es Plattformausnahmen?
Behandelt SQLite3 den gleichzeitigen Zugriff durch mehrere Prozesse, die aus derselben Datenbank lesen / schreiben, sicher? Gibt es Plattformausnahmen?
Antworten:
Wenn die meisten dieser gleichzeitigen Zugriffe gelesen werden (z. B. SELECT), kann SQLite sie sehr gut verarbeiten. Wenn Sie jedoch gleichzeitig mit dem Schreiben beginnen, kann ein Sperrenkonflikt zu einem Problem werden. Viel hängt dann davon ab, wie schnell Ihr Dateisystem ist, da die SQLite-Engine selbst extrem schnell ist und viele clevere Optimierungen aufweist, um Konflikte zu minimieren. Besonders SQLite 3.
Für die meisten Desktop- / Laptop- / Tablet- / Telefonanwendungen ist SQLite schnell genug, da nicht genügend Parallelität besteht. (Firefox verwendet SQLite häufig für Lesezeichen, Verlauf usw.)
Für Serveranwendungen hat vor einiger Zeit jemand gesagt, dass weniger als 100.000 Seitenaufrufe pro Tag in typischen Szenarien (z. B. Blogs, Foren) von einer SQLite-Datenbank perfekt verarbeitet werden können, und ich habe noch keine gegenteiligen Beweise gefunden. Tatsächlich würden mit modernen Festplatten und Prozessoren 95% der Websites und Webdienste mit SQLite einwandfrei funktionieren.
Wenn Sie einen sehr schnellen Lese- / Schreibzugriff wünschen, verwenden Sie eine speicherinterne SQLite-Datenbank . RAM ist mehrere Größenordnungen schneller als Festplatte.
Ja, SQLite verarbeitet Parallelität gut, aber unter Leistungsgesichtspunkten ist es nicht das Beste. Soweit ich das beurteilen kann, gibt es keine Ausnahmen. Die Details finden Sie auf der SQLite-Website: https://www.sqlite.org/lockingv3.html
Diese Aussage ist von Interesse: "Das Pager-Modul stellt sicher, dass Änderungen auf einmal vorgenommen werden, dass entweder alle Änderungen vorgenommen werden oder keine, dass zwei oder mehr Prozesse nicht gleichzeitig versuchen, auf inkompatible Weise auf die Datenbank zuzugreifen."
Ja tut es. Lassen Sie uns herausfinden, warum
Alle Änderungen innerhalb einer einzelnen Transaktion in SQLite erfolgen entweder vollständig oder gar nicht
Diese ACID-Unterstützung sowie das gleichzeitige Lesen / Schreiben werden auf zwei Arten bereitgestellt: mithilfe des sogenannten Journaling (nennen wir es " alte Methode ") oder der Vorausschreibprotokollierung (nennen wir es " neue Methode") ").
In diesem Modus verwendet SQLite die Sperre DATABASE-LEVEL . Dies ist der entscheidende Punkt zu verstehen.
Das heißt, wann immer es etwas lesen / schreiben muss, erhält es zuerst eine Sperre für das GESAMTE Datenbankdatei. Mehrere Leser können nebeneinander existieren und etwas parallel lesen
Während des Schreibens wird sichergestellt, dass eine exklusive Sperre erworben wird und keine andere Prozess gleichzeitig liest / schreibt, und daher sind Schreibvorgänge sicher.
Aus diesem Grund heißt es hier , dass SQlite serialisierbare Transaktionen implementiert
Da jedes Mal eine gesamte Datenbank gesperrt werden muss und jeder auf einen Prozess wartet, bei dem das Schreiben von Parallelität leidet, leiden solche gleichzeitigen Schreib- / Lesevorgänge von relativ geringer Leistung
Bevor SQLite etwas in die Datenbankdatei schreibt, speichert es zunächst den zu ändernden Block in einer temporären Datei. Wenn während des Schreibens in die Datenbankdatei etwas abstürzt, wird diese temporäre Datei abgerufen und die Änderungen werden rückgängig gemacht
In diesem Fall werden alle Schreibvorgänge an eine temporäre Datei angehängt ( Write-Ahead-Protokoll) ) und diese Datei wird regelmäßig mit der ursprünglichen Datenbank zusammengeführt. Wenn SQLite nach etwas sucht, überprüft es zuerst diese temporäre Datei. Wenn nichts gefunden wird, fahren Sie mit der Hauptdatenbankdatei fort.
Infolgedessen konkurrieren die Leser nicht mit Schriftstellern, und die Leistung ist im Vergleich zum Old Way viel besser.
SQlite hängt stark von der zugrunde liegenden Sperrfunktion des Dateisystems ab, daher sollte es mit Vorsicht verwendet werden. Weitere Details finden Sie hier
Es ist auch wahrscheinlich, dass Sie auf einen gesperrten Datenbankfehler stoßen, insbesondere im Journalmodus. Daher muss Ihre App unter Berücksichtigung dieses Fehlers entworfen werden
Niemand scheint den WAL-Modus (Write Ahead Log) erwähnt zu haben. Stellen Sie sicher, dass die Transaktionen ordnungsgemäß organisiert sind und der WAL-Modus aktiviert ist. Sie müssen die Datenbank nicht gesperrt halten, während Benutzer während eines Updates Dinge lesen.
Das einzige Problem ist, dass die WAL irgendwann wieder in die Hauptdatenbank aufgenommen werden muss, und dies geschieht, wenn die letzte Verbindung zur Datenbank geschlossen wird. Bei einer stark ausgelasteten Site kann es einige Sekunden dauern, bis alle Verbindungen geschlossen sind, aber 100.000 Treffer pro Tag sollten kein Problem sein.
database is locked
Fehler vom Verfasser
Im Jahr 2019 gibt es zwei neue Optionen für das gleichzeitige Schreiben, die noch nicht veröffentlicht wurden, aber in separaten Filialen verfügbar sind.
Der Vorteil dieses Journalmodus gegenüber dem regulären "Wal" -Modus besteht darin, dass Autoren weiterhin in eine Wal-Datei schreiben können, während die andere mit einem Prüfpunkt versehen ist.
CONCURRENT BEGINNEN - Link zum detaillierten Dokument
Mit der Erweiterung BEGIN CONCURRENT können mehrere Writer Schreibtransaktionen gleichzeitig verarbeiten, wenn sich die Datenbank im Modus "wal" oder "wal2" befindet, obwohl das System weiterhin COMMIT-Befehle serialisiert.
Wenn eine Schreibtransaktion mit "BEGIN CONCURRENT" geöffnet wird, wird das tatsächliche Sperren der Datenbank verschoben, bis ein COMMIT ausgeführt wird. Dies bedeutet, dass eine beliebige Anzahl von Transaktionen, die mit BEGIN CONCURRENT gestartet wurden, gleichzeitig ausgeführt werden können. Das System verwendet eine optimistische Sperre auf Seitenebene, um zu verhindern, dass widersprüchliche gleichzeitige Transaktionen festgeschrieben werden.
Zusammen sind sie in begin-concurrent-wal2 oder jeweils in einem eigenen Zweig vorhanden .
begin concurrent
Zeug gepusht .
SQLite verfügt über eine Readers-Writer-Sperre auf Datenbankebene. Mehrere Verbindungen (möglicherweise im Besitz verschiedener Prozesse) können gleichzeitig Daten aus derselben Datenbank lesen, aber nur eine kann in die Datenbank schreiben.
SQLite unterstützt eine unbegrenzte Anzahl gleichzeitiger Leser, erlaubt jedoch zu jedem Zeitpunkt nur einen Schreiber. In vielen Situationen ist dies kein Problem. Warteschlange für Autoren. Jede Anwendung erledigt ihre Datenbankarbeit schnell und geht weiter, und keine Sperre dauert länger als ein paar Dutzend Millisekunden. Es gibt jedoch einige Anwendungen, die mehr Parallelität erfordern, und diese Anwendungen müssen möglicherweise nach einer anderen Lösung suchen. - Geeignete Verwendungen für SQLite @ SQLite.org
Die Readers-Writer-Sperre ermöglicht eine unabhängige Transaktionsverarbeitung und wird mithilfe exklusiver und gemeinsam genutzter Sperren auf Datenbankebene implementiert.
Eine exklusive Sperre muss eingeholt werden, bevor eine Verbindung eine Schreiboperation für eine Datenbank ausführt. Nachdem die exklusive Sperre erhalten wurde, werden sowohl Lese- als auch Schreibvorgänge von anderen Verbindungen blockiert, bis die Sperre wieder aufgehoben wird.
SQLite verfügt über eine Sperrtabelle, mit deren Hilfe die Datenbank während eines Schreibvorgangs so spät wie möglich gesperrt werden kann, um maximale Parallelität zu gewährleisten.
Der Anfangszustand ist UNLOCKED, und in diesem Zustand hat die Verbindung noch nicht auf die Datenbank zugegriffen. Wenn ein Prozess mit einer Datenbank verbunden ist und sogar eine Transaktion mit BEGIN gestartet wurde, befindet sich die Verbindung immer noch im Status UNLOCKED.
Nach dem Status UNLOCKED ist der nächste Status der Status SHARED. Um Daten aus der Datenbank lesen (nicht schreiben) zu können, muss die Verbindung zuerst in den Status SHARED versetzt werden, indem eine SHARED-Sperre aktiviert wird. Mehrere Verbindungen können gleichzeitig gemeinsam genutzte Sperren erhalten und verwalten, sodass mehrere Verbindungen gleichzeitig Daten aus derselben Datenbank lesen können. Solange jedoch nur eine SHARED-Sperre nicht freigegeben ist, kann keine Verbindung einen Schreibvorgang in die Datenbank erfolgreich abschließen.
Wenn eine Verbindung in die Datenbank schreiben möchte, muss sie zuerst eine RESERVIERTE Sperre erhalten.
Es kann immer nur eine einzige RESERVIERTE Sperre gleichzeitig aktiv sein, obwohl mehrere gemeinsam genutzte Sperren mit einer einzelnen RESERVIERTEN Sperre koexistieren können. RESERVIERT unterscheidet sich von PENDING dadurch, dass neue SHARED-Sperren erworben werden können, während eine RESERVIERTE Sperre vorhanden ist. - Dateisperrung und Parallelität in SQLite Version 3 @ SQLite.org
Sobald eine Verbindung eine RESERVIERTE Sperre erhält, kann sie mit der Verarbeitung von Datenbankänderungsvorgängen beginnen. Diese Änderungen können jedoch nur im Puffer vorgenommen werden, anstatt tatsächlich auf die Festplatte geschrieben zu werden. Die am Ausleseinhalt vorgenommenen Änderungen werden im Speicherpuffer gespeichert. Wenn eine Verbindung eine Änderung (oder Transaktion) senden möchte, muss die RESERVIERTE Sperre auf eine EXKLUSIVE Sperre aktualisiert werden. Um das Schloss zu erhalten, müssen Sie das Schloss zuerst auf ein PENDING-Schloss heben.
Eine PENDING-Sperre bedeutet, dass der Prozess, der die Sperre hält, so schnell wie möglich in die Datenbank schreiben möchte und nur darauf wartet, dass alle aktuellen SHARED-Sperren gelöscht werden, damit er eine EXKLUSIVE Sperre erhält. Es sind keine neuen SHARED-Sperren für die Datenbank zulässig, wenn eine PENDING-Sperre aktiv ist, obwohl vorhandene SHARED-Sperren fortgesetzt werden dürfen.
Eine EXKLUSIVE Sperre ist erforderlich, um in die Datenbankdatei zu schreiben. Es ist nur eine EXKLUSIVE Sperre für die Datei zulässig, und es dürfen keine anderen Sperren jeglicher Art mit einer EXKLUSIVEN Sperre koexistieren. Um die Parallelität zu maximieren, minimiert SQLite die Zeit, die EXKLUSIVE Sperren gehalten werden. - Dateisperrung und Parallelität in SQLite Version 3 @ SQLite.org
Sie können also sagen, dass SQLite den gleichzeitigen Zugriff durch mehrere Prozesse, die in dieselbe Datenbank schreiben, sicher verarbeitet, nur weil es dies nicht unterstützt! Sie erhalten SQLITE_BUSY
oder SQLITE_LOCKED
für den zweiten Schreiber, wenn er die Wiederholungsbeschränkung erreicht.
Dieser Thread ist alt, aber ich denke, es wäre gut, das Ergebnis meiner auf SQLite durchgeführten Tests zu teilen: Ich habe 2 Instanzen des Python-Programms (verschiedene Prozesse, dasselbe Programm) ausgeführt, wobei die Anweisungen SELECT und UPDATE SQL-Befehle innerhalb der Transaktion ausgeführt wurden, wobei EXCLUSIVE lock und Timeout auf gesetzt waren 10 Sekunden, um eine Sperre zu erhalten, und das Ergebnis war frustrierend. Jede Instanz hat in 10000 Schrittschleifen:
Selbst wenn SQLite eine exklusive Sperre für Transaktionen gewährt hat, war die Gesamtzahl der tatsächlich ausgeführten Zyklen nicht gleich 20 000, sondern geringer (Gesamtzahl der Iterationen über einen einzelnen Zähler, die für beide Prozesse gezählt wurden). Das Python-Programm hat fast keine einzige Ausnahme ausgelöst (nur einmal während der Auswahl für 20 Ausführungen). Die SQLite-Revision zum Zeitpunkt des Tests war 3.6.20 und Python v3.3 CentOS 6.5. Meiner Meinung nach ist es besser, ein zuverlässigeres Produkt für diese Art von Arbeit zu finden oder Schreibvorgänge auf SQLite auf einen einzelnen Prozess / Thread zu beschränken.
with con
ausreicht.