[英]Improve UPDATE-per-second performance of SQLite?
我的問題直接來自這個問題,雖然我只對UPDATE感興趣並且只對此感興趣。
我有一個用C/C++
編寫的應用程序,它在非常頻繁的時間間隔內大量使用SQLite
(主要是SELECT/UPDATE
(每0.5到1秒約20次查詢)
我的數據庫不大, 此刻約有2500條記錄,這里是表結構:
CREATE TABLE player (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(64) UNIQUE,
stats VARBINARY,
rules VARBINARY
);
到目前為止,我沒有使用transactions
因為我正在改進代碼並希望穩定而不是性能。
然后我通過僅執行10 update
查詢來測量我的數據庫性能,以下(在不同值的循環中):
// 10 times execution of this
UPDATE player SET stats = ? WHERE (name = ?)
其中stats
是一個恰好150個字符的JSON, name
是5-10個字符。
沒有交易,結果是不可接受的: - 大約1整秒(每個0.096)
隨着交易,時間下降x7.5倍: - 約0.11 - 0.16秒(每個0.013)
我嘗試刪除數據庫的大部分和/或重新排序/刪除列,以查看是否有任何改變,但事實並非如此。 即使數據庫只包含100條記錄 (已測試),我也會得到上述數字。
然后我嘗試使用PRAGMA
選項:
PRAGMA synchronous = NORMAL
PRAGMA journal_mode = MEMORY
給了我較小的時間但不總是,更像是0.08 - 0.14秒
PRAGMA synchronous = OFF
PRAGMA journal_mode = MEMORY
最后給了我非常小的時間大約0.002 - 0.003秒,但我不想使用它,因為我的應用程序每秒保存數據庫,並且很有可能在操作系統/電源故障時數據庫損壞。
我的C SQLite
查詢代碼是:(注釋/錯誤處理/無關的部分省略)
// 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);
如你所見,它是一個非常典型的TABLE
,記錄數量很小,而且我正在進行簡單的簡單UPDATE
10次。 我還能做些什么來減少我的UPDATE
時間嗎? 我正在使用最新的SQLite 3.16.2
。
注意:上面的時間直接來自單個
END TRANSACTION
查詢。 查詢是在一個簡單的事務中完成的,我正在使用一個准備好的語句。
更新:
我在執行啟用和禁用事務以及各種更新計數時執行了一些測試。 我使用以下設置執行測試:
VACUUM;
PRAGMA synchronous = NORMAL; -- def: FULL
PRAGMA journal_mode = WAL; -- def: DELETE
PRAGMA page_size = 4096; -- def: 1024
結果如下:
沒有交易(10次更新)
沒有交易(100次更新)
沒有交易(1000次更新)
交易(10次更新)
交易(100次更新)
交易(1000次更新)
我的結論是,對於transactions
, time cost per query
沒有任何意義。 也許隨着更新次數的增加,時代變得越來越大,但我對這些數字並不感興趣。 單個交易的10到1000次更新之間幾乎沒有時間成本差異。 但是,我想知道這是否是我的機器上的硬件限制,並不能做太多。 似乎我不能使用單個事務超過~100
毫秒,並且即使使用WAL也可以進行10-1000次更新。
沒有交易,固定時間成本約為0.025
秒。
您可能仍然受限於提交交易所需的時間。 在您的第一個示例中,每個事務大約需要0.10才能完成,這非常接近插入10條記錄的事務時間。 如果您在單個交易中批量100或1000次更新,您會得到什么樣的結果?
此外,SQLite預計平均硬盤驅動器每秒大約有60個事務處理,而你只能得到10個左右。這可能是你的磁盤性能問題嗎?
由於數據量很小,數據庫操作本身的時間是微不足道的; 您測量的是事務開銷(強制寫入磁盤所需的時間),這取決於操作系統,文件系統和硬件。
如果您可以忍受其限制(主要是沒有網絡),則可以通過啟用WAL模式來使用異步寫入。
嘗試將INDEXE添加到您的數據庫:
CREATE INDEX IDXname ON player (name)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.