Was sind die Leistungsmerkmale von SQLite mit sehr großen Datenbankdateien? [geschlossen]


325

Ich weiß, dass SQLite mit extrem großen Datenbankdateien nicht gut funktioniert, selbst wenn sie unterstützt werden (auf der SQLite-Website gab es früher einen Kommentar, der besagt, dass Sie bei Verwendung von Dateigrößen über 1 GB möglicherweise die Verwendung eines Unternehmens-RDBMS in Betracht ziehen sollten finde es nicht mehr, könnte mit einer älteren Version von sqlite zusammenhängen).

Für meine Zwecke möchte ich jedoch eine Vorstellung davon bekommen, wie schlimm es wirklich ist, bevor ich über andere Lösungen nachdenke.

Ich spreche von SQLite-Datendateien im Multi-Gigabyte-Bereich ab 2 GB. Hat jemand irgendwelche Erfahrungen damit? Irgendwelche Tipps / Ideen?


1
Die Verwendung von Threading (Verbindung pro Thread) kann nur zum Lesen hilfreich sein
stackoverflow.com/a/24029046/743263


23
Jahr 2016: Ich habe eine 5-GB-Datenbank, die problemlos auf SQLite ausgeführt wird. Ich habe genau den gleichen Datensatz auf Postgres installiert. SQLite führte eine komplexe Abfrage in 2,7 ms aus, Postgres in 2,5 ms. Ich bin auf Postgres gelandet, um den Regex-Zugriff zu erleichtern und die Indexfunktionen zu verbessern. Aber ich war beeindruckt von SQLite und hätte es auch verwenden können.
Paulb

Antworten:


246

Also habe ich einige Tests mit SQLite für sehr große Dateien durchgeführt und bin zu einigen Schlussfolgerungen gekommen (zumindest für meine spezifische Anwendung).

Die Tests umfassen eine einzelne SQLite-Datei mit entweder einer einzelnen Tabelle oder mehreren Tabellen. Jede Tabelle hatte ungefähr 8 Spalten, fast alle ganzen Zahlen und 4 Indizes.

Die Idee war, genügend Daten einzufügen, bis die SQLite-Dateien etwa 50 GB groß waren.

Einzelne Tabelle

Ich habe versucht, mehrere Zeilen mit nur einer Tabelle in eine SQLite-Datei einzufügen. Als die Datei ungefähr 7 GB groß war (leider kann ich die Anzahl der Zeilen nicht genau bestimmen), dauerte das Einfügen viel zu lange. Ich hatte geschätzt, dass mein Test zum Einfügen aller meiner Daten ungefähr 24 Stunden dauern würde, aber er wurde auch nach 48 Stunden nicht abgeschlossen.

Dies lässt mich zu dem Schluss kommen, dass eine einzelne, sehr große SQLite-Tabelle Probleme mit Einfügungen und wahrscheinlich auch mit anderen Operationen haben wird.

Ich denke, das ist keine Überraschung, da die Tabelle größer wird und das Einfügen und Aktualisieren aller Indizes länger dauert.

Mehrere Tabellen

Ich habe dann versucht, die Daten nach Zeit auf mehrere Tabellen aufzuteilen, eine Tabelle pro Tag. Die Daten für die ursprüngliche 1-Tabelle wurden auf ~ 700 Tabellen aufgeteilt.

Dieses Setup hatte keine Probleme mit dem Einfügen, es dauerte im Laufe der Zeit nicht länger, da für jeden Tag eine neue Tabelle erstellt wurde.

Vakuumprobleme

Wie von i_like_caffeine hervorgehoben, ist der Befehl VACUUM ein Problem, je größer die SQLite-Datei ist. Je mehr Einfügungen / Löschvorgänge durchgeführt werden, desto schlechter wird die Fragmentierung der Datei auf der Festplatte. Daher besteht das Ziel darin, regelmäßig VACUUM zu verwenden, um die Datei zu optimieren und den Dateibereich wiederherzustellen.

Wie aus der Dokumentation hervorgeht , wird jedoch eine vollständige Kopie der Datenbank erstellt, um ein Vakuum zu erzeugen, was sehr lange dauert. Je kleiner die Datenbank ist, desto schneller wird dieser Vorgang abgeschlossen.

Schlussfolgerungen

Für meine spezielle Anwendung werde ich wahrscheinlich Daten auf mehrere Datenbankdateien aufteilen, eine pro Tag, um die Vakuumleistung und die Einfüge- / Löschgeschwindigkeit optimal zu nutzen.

Dies erschwert Abfragen, aber für mich ist es ein lohnender Kompromiss, so viele Daten indizieren zu können. Ein zusätzlicher Vorteil ist, dass ich einfach eine ganze Datenbankdatei löschen kann, um Daten im Wert von einem Tag zu löschen (ein üblicher Vorgang für meine Anwendung).

Ich müsste wahrscheinlich auch die Tabellengröße pro Datei überwachen, um zu sehen, wann die Geschwindigkeit zum Problem wird.

Es ist schade, dass es keine andere inkrementelle Vakuummethode als das automatische Vakuum zu geben scheint . Ich kann es nicht verwenden, da mein Ziel für Vakuum darin besteht, die Datei zu defragmentieren (Dateibereich ist keine große Sache), was beim automatischen Vakuum nicht der Fall ist. Tatsächlich besagt die Dokumentation, dass dies die Fragmentierung verschlimmern kann, sodass ich regelmäßig ein vollständiges Vakuum für die Datei durchführen muss.


5
Sehr nützliche Infos. Reine Spekulation, aber ich frage mich, ob die neue Backup-API verwendet werden kann, um täglich eine nicht fragmentierte Version Ihrer Datenbank zu erstellen und die Notwendigkeit zu vermeiden, ein VACUUM auszuführen.
Eodonohoe

24
Ich bin neugierig, waren alle Ihre INSERTS in einer Transaktion?
Paul Lefebvre

9
Ja, Einfügungen wurden in Stapeln von 10000 Nachrichten pro Transaktion durchgeführt.
Snazzer

6
Welches Dateisystem haben Sie verwendet? Wenn ext {2,3,4}, wie lautete die Einstellung data =, wurde das Journaling aktiviert? Neben io-Mustern kann die Art und Weise, wie SQLite auf die Festplatte gespült wird, von Bedeutung sein.
Tobu

5
Ich habe hauptsächlich unter Windows getestet, kann also das Verhalten unter Linux nicht kommentieren.
Snazzer

169

Wir verwenden DBS von 50 GB + auf unserer Plattform. Keine Beschwerden funktionieren super. Stellen Sie sicher, dass Sie alles richtig machen! Verwenden Sie vordefinierte Anweisungen? * SQLITE 3.7.3

  1. Transaktionen
  2. Vorab gemachte Aussagen
  3. Wenden Sie diese Einstellungen an (direkt nach dem Erstellen der Datenbank).

    PRAGMA main.page_size = 4096;
    PRAGMA main.cache_size=10000;
    PRAGMA main.locking_mode=EXCLUSIVE;
    PRAGMA main.synchronous=NORMAL;
    PRAGMA main.journal_mode=WAL;
    PRAGMA main.cache_size=5000;

Hoffe das wird anderen helfen, funktioniert hier super


22
Kürzlich mit dbs im Bereich von 160 GB getestet, funktioniert auch hervorragend.
Snazzer

10
Auch PRAGMA main.temp_store = MEMORY;.
Vikrant Chaudhary

40
@Alex, warum gibt es zwei PRAGMA main.cache_size = 5000;?
Jack

23
Wenden Sie diese Optimierungen nicht einfach blind an. Insbesondere synchron = NORMAL ist nicht absturzsicher. Das heißt, ein Prozessabsturz zum richtigen Zeitpunkt kann Ihre Datenbank auch dann beschädigen, wenn keine Festplattenfehler vorliegen. sqlite.org/pragma.html#pragma_synchronous
mpm

22
@Alex kannst du bitte diese Werte und den Unterschied zwischen ihnen und den Standardwerten erklären?
4m1nh4j1

65

Ich habe SQLite-Datenbanken mit einer Größe von bis zu 3,5 GB ohne erkennbare Leistungsprobleme erstellt. Wenn ich mich richtig erinnere, hatte SQLite2 möglicherweise einige niedrigere Grenzwerte, aber ich glaube nicht, dass SQLite3 solche Probleme hat.

Laut der Seite SQLite Limits beträgt die maximale Größe jeder Datenbankseite 32 KB. Und die maximale Anzahl von Seiten in einer Datenbank beträgt 1024 ^ 3. Nach meiner Berechnung ergibt sich also eine maximale Größe von 32 Terabyte. Ich denke, Sie werden die Grenzen Ihres Dateisystems erreichen, bevor Sie SQLites erreichen!


3
Je nachdem, welche Vorgänge Sie ausführen und 3000 Zeilen in einer 8G-SQLite-Datenbank löschen, dauert es genug Zeit, bis Sie einen schönen Topf French Press brauen, lol
benjaminz

4
@benjaminz, du musst es falsch machen. Wenn Sie das Löschen von 3.000 Zeilen in eine Transaktion einschließen, sollte dies fast sofort erfolgen. Ich hatte selbst diesen Fehler: Das Löschen von 10.000 Zeilen nacheinander dauerte 30 Minuten. Aber nachdem ich alle Löschanweisungen in eine Transaktion eingeschlossen hatte, dauerte es 5 Sekunden.
MVP

55

Der Hauptgrund dafür, dass das Einfügen Ihrer Einfügungen> 48 Stunden dauerte, liegt in Ihren Indizes. Es ist unglaublich schneller zu:

1 - Alle Indizes löschen 2 - Alle Einfügungen durchführen 3 - Indizes erneut erstellen


23
Das ist bekannt ... aber für einen langen Prozess werden Sie Ihre Indizes nicht regelmäßig löschen, um sie neu zu erstellen, insbesondere wenn Sie sie abfragen, um ihre Arbeit zu erledigen. Dies ist der Ansatz, der verfolgt wird, wenn die SQLite-Datenbank von Grund auf neu erstellt werden muss. Die Indizes werden erstellt, nachdem alle Einfügungen abgeschlossen sind.
Snazzer

24
@Snazzer In einer ähnlichen Situation haben wir eine "Akkumulator" -Tabelle verwendet: Einmal pro Tag haben wir dann die akkumulierten Zeilen innerhalb einer einzigen Transaktion von der Akkumulator-Tabelle in die Haupttabelle verschoben. Bei Bedarf sorgte eine Ansicht dafür, dass beide Tabellen als eine einzige Tabelle dargestellt wurden.
CAFxX

4
Eine andere Möglichkeit besteht darin, die Indizes beizubehalten, die Daten jedoch vor dem Einfügen in Indexreihenfolge vorsortieren.
Steven Kryskalla

1
@StevenKryskalla Wie ist das im Vergleich zum Löschen und Neuerstellen der Indizes? Haben Sie Links, von denen Sie wissen, dass sie ein Benchmarking durchgeführt haben?
Mcmillab

1
@mcmillab Das war vor Jahren, daher erinnere ich mich nicht an alle Details oder Benchmark-Statistiken, aber wenn ich intuitiv denke, dauert das Einfügen von N zufällig angeordneten Elementen in einen Index O (NlogN), während das Einfügen von N sortierten Elementen O (N) benötigt ) Zeit.
Steven Kryskalla

34

Neben der üblichen Empfehlung:

  1. Drop-Index für Masseneinfügung.
  2. Batch-Einfügungen / Aktualisierungen bei großen Transaktionen.
  3. Optimieren Sie Ihren Puffer-Cache / deaktivieren Sie das Journal / w PRAGMAs.
  4. Verwenden Sie einen 64-Bit-Computer (um viel Cache ™ verwenden zu können).
  5. [hinzugefügt im Juli 2014] Verwenden Sie Common Table Expression (CTE), anstatt mehrere SQL-Abfragen auszuführen! Benötigt SQLite Release 3.8.3.

Ich habe aus meinen Erfahrungen mit SQLite3 Folgendes gelernt:

  1. Verwenden Sie für eine maximale Einfügegeschwindigkeit kein Schema mit Spalteneinschränkungen. ((Ändern Sie die Tabelle später nach Bedarf Sie können mit ALTER TABLE keine Einschränkungen hinzufügen.
  2. Optimieren Sie Ihr Schema, um das zu speichern, was Sie benötigen. Manchmal bedeutet dies, Tabellen aufzuschlüsseln und / oder sogar Ihre Daten zu komprimieren / zu transformieren, bevor Sie sie in die Datenbank einfügen. Ein gutes Beispiel ist das Speichern von IP-Adressen als (lange) Ganzzahlen.
  3. Eine Tabelle pro Datenbankdatei - um Sperrkonflikte zu minimieren. (Verwenden Sie ATTACH DATABASE, wenn Sie ein einzelnes Verbindungsobjekt haben möchten.
  4. SQLite kann verschiedene Datentypen in derselben Spalte speichern (dynamische Typisierung). Nutzen Sie dies zu Ihrem Vorteil.

Frage / Kommentar willkommen. ;-);


1
Wie stark wirkt sich eine Tabelle pro Datenbankdatei aus? Hört sich interessant an. Denken Sie, es wäre wichtig, wenn Ihr Tisch nur 3 Tische hat und von Grund auf neu gebaut wird?
Martin Velez

4
@martin hasse es zu sagen, aber die Antwort ist, es kommt darauf an . Die Idee ist, die Daten auf eine überschaubare Größe zu partitionieren. In meinem Anwendungsfall sammle ich Daten von verschiedenen Hosts und erstelle nachträglich Bericht über die Daten, sodass dieser Ansatz gut funktioniert hat. Die von anderen vorgeschlagene Partitionierung nach Datum / Uhrzeit sollte für Daten, die sich über einen langen Zeitraum erstrecken, wie ich mir vorstellen kann, gut funktionieren.
Lester Cheung

3
@Lester Cheung: In Bezug auf Ihre zweite Nummer 1: Nach meinem Verständnis aus den Dokumenten und persönlichen Erfahrungen unterstützt SQLite3 bis heute das Hinzufügen von Einschränkungen mit ALTER TABLE nach der Erstellung der Tabelle nicht. Die einzige Möglichkeit, Einschränkungen zu vorhandenen Tabellenzeilen hinzuzufügen oder daraus zu entfernen, besteht darin, eine neue Tabelle mit den gewünschten Merkmalen zu erstellen und über alle Zeilen zu kopieren. Dies ist wahrscheinlich viel langsamer als das einmalige Einfügen mit Einschränkungen.
Mumbleskates

3
@Widdershins Sie haben absolut Recht - ALTER TABLE in SQLite erlaubt kein Hinzufügen von Einschränkungen. Ich weiß nicht, was ich geraucht habe - werde die Antwort aktualisieren - danke.
Lester Cheung

Keiner dieser Vorschläge hat etwas mit der Verwendung von riesigen SQLite-Datenbankdateien zu tun. Wurde die Frage bearbeitet, seit diese Antwort eingereicht wurde?
A. Rager

9

Ich denke, die Hauptbeschwerden über die SQLite-Skalierung sind:

  1. Einzelprozess schreiben.
  2. Keine Spiegelung.
  3. Keine Replikation.

9

Ich habe eine 7 GB SQLite-Datenbank. Das Ausführen einer bestimmten Abfrage mit einem inneren Join dauert 2,6 Sekunden. Um dies zu beschleunigen, habe ich versucht, Indizes hinzuzufügen. Je nachdem, welche Indizes ich hinzugefügt habe, ging die Abfrage manchmal auf 0,1 Sekunden und manchmal auf 7 Sekunden zurück. Ich denke, das Problem in meinem Fall war, dass das Hinzufügen eines Index die Leistung beeinträchtigt, wenn eine Spalte stark dupliziert wird :(


9
Warum würde eine Spalte mit vielen Duplikaten die Leistung beeinträchtigen (ernsthafte Frage)?
Martin Velez

6
eine Spalte mit geringer Mächtigkeit ist härter zu indizieren: stackoverflow.com/questions/2113181/...
metrix

9

In der SQLite-Dokumentation gab es früher eine Aussage, dass die praktische Größenbeschränkung einer Datenbankdatei einige Dutzend GB: s betrug. Dies lag hauptsächlich daran, dass SQLite bei jedem Start einer Transaktion "eine Bitmap schmutziger Seiten zuweisen" musste. Somit waren 256 Byte RAM für jedes MB in der Datenbank erforderlich. Das Einfügen in eine 50-GB-DB-Datei würde kräftige (2 ^ 8) * (2 ^ 10) = 2 ^ 18 = 256 MB RAM erfordern.

Ab den neuesten Versionen von SQLite wird dies jedoch nicht mehr benötigt. Lesen Sie hier mehr .


25
Es tut mir sehr leid, dass ich darauf hinweisen muss, aber 2^18tatsächlich sind es nur 256 K.
Gabriel Schreiber

7
@ GabrielSchreiber das, und auch die Tatsache, dass 50 GB nicht (2 ^ 10) MB sind, das sind nur 1 GB. Für eine 50-GB-Datenbank benötigen Sie also 12,5 MB Speicher: (2 ^ 8) * (2 ^ 10) * 50
elipoultorak

8

Bei der Verwendung des Befehls vakuum sind Probleme mit großen SQLite-Dateien aufgetreten.

Ich habe die Funktion auto_vacuum noch nicht ausprobiert. Wenn Sie erwarten, dass Daten häufig aktualisiert und gelöscht werden, ist dies einen Blick wert.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.