繁体   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