Meine Frage kommt direkt aus this ein, obwohl ich nur an UPDATE interessiert bin und nur das.Verbessern UPDATE-pro-Sekunde-Leistung von SQLite?
Ich habe eine Anwendung in C/C++
geschrieben, die starke Nutzung von SQLite
macht, meist SELECT/UPDATE
, auf einem sehr häufigen Intervall (ca. 20 Abfragen alle 0,5 bis 1 Sekunde)
Meine Datenbank ist nicht groß, etwa hier ist 2500 Aufzeichnungen in den Momenten, die Struktur der Tabelle:
CREATE TABLE player (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(64) UNIQUE,
stats VARBINARY,
rules VARBINARY
);
bis zu diesem Punkt, den ich nicht transactions
verwendet habe, weil ich den Code wurde verbessert und wollte stab eher Leistung.
Dann maß ich meine Datenbank-Performance von lediglich 10 update
Ausführen von Abfragen, die folgenden (in einer Schleife von unterschiedlichen Werten): ist
// 10 times execution of this
UPDATE player SET stats = ? WHERE (name = ?)
wo stats
ist ein JSON von genau 150 Zeichen und name
von 5 bis 10 Figuren.
Ohne Transaktionen, ist das Ergebnis nicht akzeptabel: - etwa 1 volle Sekunde (0,096 each)
mit den Transaktionen, fällt die Zeit x7.5 Zeiten: - etwa 0,11 - 0,16 Sekunden (0,013 each)
Ich versuchte, einen großen Teil der Datenbank zu löschen und/oder Spalten neu anzuordnen/zu löschen, um zu sehen, ob sich das ändert, aber es tat es nicht. Ich bekomme die obigen Zahlen auch wenn die Datenbank nur 100 Datensätze (getestet) enthält.
Ich habe dann versucht, mit PRAGMA
Optionen spielen:
PRAGMA synchronous = NORMAL
PRAGMA journal_mode = MEMORY
Gab mir kleinere Zeiten, aber nicht immer, eher wie etwa 0,08 - 0,14 Sekunden
PRAGMA synchronous = OFF
PRAGMA journal_mode = MEMORY
Schließlich gab mir extrem kleine Zeiten etwa 0,002 - 0,003 Sekunden, aber ich möchte es nicht verwenden, da meine Anwendung die Datenbank jede Sekunde speichert und die Wahrscheinlichkeit einer beschädigten Datenbank sehr hoch ist n OS/Stromausfall.
Mein C SQLite
Code für Abfragen ist: (Kommentare/Fehlerbehandlung/ohne Bezug Teile weggelassen)
// start transaction
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL);
// query
sqlite3_stmt *statement = NULL;
int out = sqlite3_prepare_v2(query.c_str(), -1, &statement, NULL);
// bindings
for(size_t x = 0, sz = bindings.size(); x < sz; x++) {
out = sqlite3_bind_text(statement, x+1, bindings[x].text_value.c_str(), bindings[x].text_value.size(), SQLITE_TRANSIENT);
...
}
// execute
out = sqlite3_step(statement);
if (out != SQLITE_OK) {
// should finalize the query no mind the error
if (statement != NULL) {
sqlite3_finalize(statement);
}
}
// end the transaction
sqlite3_exec(db, "END TRANSACTION", NULL, NULL, NULL);
Wie Sie sehen, es ist ein ziemlich typisches TABLE
zeichnet Zahl ist klein und ich bin ein einfache einfach tun UPDATE
genau 10 mal. Gibt es noch etwas, was ich tun könnte, um meine UPDATE
Zeiten zu verringern? Ich benutze die neueste SQLite 3.16.2
.
HINWEIS: Die Zeiten oben sind direkt aus einer einzigen Abfrage
END TRANSACTION
kommen.Abfragen werden in einer einfachen Transaktion durchgeführt und ich bin mit einer vorbereiteten Anweisung.
UPDATE:
Ich führte einige Tests mit der Transaktion aktiviert und deaktiviert und verschiedene Updates zählen. Ich führte die Tests mit den folgenden Einstellungen:
VACUUM;
PRAGMA synchronous = NORMAL; -- def: FULL
PRAGMA journal_mode = WAL; -- def: DELETE
PRAGMA page_size = 4096; -- def: 1024
Die Ergebnisse folgt:
keine Transaktionen (10 Updates)
- 0,30800 Sekunden (0,0308 pro Update)
- 0,30200 Sekunden
- 0,36200 Sekunden
- 0,28600 s ecs
keine Transaktionen (100 Updates)
- 2,64400 Sekunden (0,02644 jedes Update)
- 2,61200 Sekunden
- 2,76400 Sekunden
- 2,68700 Sekunden
keine transacti ons (1000 Updates)
- 28,02800 Sekunden (0,028 jedes Update)
- 27,73700 Sekunden
- ..
mit Transaktionen (10 Updates)
- 0,12800 Sekunden (0.0128 jedes Update)
- 0,08100 Sekunden
- 0,16400 Sekunden
- 0,10400 Sekunden
mit Transaktionen (100 Updates)
- 0,088 Sekunden (0,00088 jedes Update)
- 0,091 Sekunden
- 0.052 Sekunden
- 0.101 Sekunden
mit Transaktionen (1000 Updates)
- 0,08900 Sekunden (0,000089 jedes Update)
- 0,15000 Sekunden
- 0,11000 Sekunden
- 0,09100 Sekunden
Meine Schlussfolgerungen sind das mit transactions
gibt es keinen Sinn in time cost per query
. Vielleicht wird die Zeit mit einer riesigen Anzahl von Updates größer, aber ich bin nicht an diesen Zahlen interessiert. Es gibt buchstäblich keinen Zeitunterschied zwischen 10 und 1000 Updates für eine einzige Transaktion. Ich frage mich jedoch, ob dies ein Hardware-Limit auf meinem Rechner ist und nicht viel bewirken kann. Es scheint, ich kann nicht unter ~100
Millisekunden mit einer einzigen Transaktion und Bereich 10-1000 Updates gehen, auch mit WAL.
Ohne Transaktionen gibt es einen festen Zeitaufwand von etwa 0.025
Sekunden.
Wenn Sie die languiage C/C++ verwenden, verwenden Sie den richtigen Tag. Ansonsten sieht es aus wie C++, nicht die ** andere ** Sprache C! Und dies ist keine Code-Review-Website. – Olaf
@Olaf, das einzige 'C++' Zeug ist ein 'std :: string'; der Rest ist "C". Ich betone das ausdrücklich oben. Zweitens möchte ich nicht, dass jemand meinen Code überprüft, ich möchte einen besseren Ansatz von SQLite, um mein Problem zu lösen – user6096479
Es tut ** nicht ** kompilieren als C, also ist es nicht C. Nur weil Sie die gleiche Syntax/Grammatik haben bedeutet nicht, dass Sie die gleiche Semantik haben! Wer sagt, dass C++ "C with classes" ist, ist schlicht falsch und kennt zumindest einen von ihnen nicht gut genug, um nicht-trivialen Code zu schreiben. – Olaf