簡體   English   中英

提高SQLite的每秒UPDATE性能?

[英]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次更新)

  • 0.30800秒(每次更新0.0308)
  • 0.30200秒
  • 0.36200秒
  • 0.28600秒

沒有交易(100次更新)

  • 2.64400秒(每次更新0.02644)
  • 2.61200秒
  • 2.76400秒
  • 2.68700秒

沒有交易(1000次更新)

  • 28.02800秒(每次更新0.028)
  • 27.73700秒
  • ..

交易(10次更新)

  • 0.12800秒(每次更新0.0128)
  • 0.08100秒
  • 0.16400秒
  • 0.10400秒

交易(100次更新)

  • 0.088秒(每次更新0.00088)
  • 0.091秒
  • 0.052秒
  • 0.101秒

交易(1000次更新)

  • 0.08900秒(每次更新0.000089)
  • 0.15000秒
  • 0.11000秒
  • 0.09100秒

我的結論是,對於transactionstime cost per query沒有任何意義。 也許隨着更新次數的增加,時代變得越來越大,但我對這些數字並不感興趣。 單個交易的10到1000次更新之間幾乎沒有時間成本差異。 但是,我想知道這是否是我的機器上的硬件限制,並不能做太多。 似乎我不能使用單個事務超過~100毫秒,並且即使使用WAL也可以進行10-1000次更新。

沒有交易,固定時間成本約為0.025秒。

您可能仍然受限於提交交易所需的時間。 在您的第一個示例中,每個事務大約需要0.10才能完成,這非常接近插入10條記錄的事務時間。 如果您在單個交易中批量100或1000次更新,您會得到什么樣的結果?

此外,SQLite預計平均硬盤驅動器每秒大約有60個事務處理,而你只能得到10個左右。這可能是你的磁盤性能問題嗎?

https://sqlite.org/faq.html#q19

由於數據量很小,數據庫操作本身的時間是微不足道的; 您測量的是事務開銷(強制寫入磁盤所需的時間),這取決於操作系統,文件系統和硬件。

如果您可以忍受其限制(主要是沒有網絡),則可以通過啟用WAL模式來使用異步寫入。

嘗試將INDEXE添加到您的數據庫:

CREATE INDEX IDXname ON player (name)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM