我的问题直接来自this,但我只对 UPDATE 感兴趣而且仅对此感兴趣。
我有一个用C/C++
编写的应用程序,它在非常频繁的间隔(每0.5到1秒约20次查询)中大量使用SQLite
,主要是SELECT/UPDATE
我的数据库不大,关于 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秒但是我不想使用它,因为我的应用程序每秒都会保存数据库并且很有可能被破坏OS /电源故障数据库。
我的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次更新之间几乎没有时间成本差异。但是,我想知道这是否是我的机器上的硬件限制,并且不能做太多。使用单个事务并且即使使用WAL也可以使用10到1000次更新,我似乎不能低于~100
毫秒。
如果没有交易,固定时间成本约为0.025
秒。
答案 0 :(得分:3)
您可能仍然受限于提交交易所需的时间。在您的第一个示例中,每个事务大约需要0.10才能完成,这非常接近插入10条记录的事务时间。如果您在一次交易中批量处理100或1000次更新,会得到什么样的结果?
此外,SQLite预计普通硬盘每秒大约有60笔交易,而你的大约只有10笔。这可能是你的磁盘性能问题吗?
答案 1 :(得分:3)
如此少量的数据,数据库操作本身的时间是微不足道的;您正在测量的是事务开销(强制写入磁盘所需的时间),这取决于操作系统,文件系统和硬件。
如果您可以忍受其限制(主要是没有网络),您可以通过启用WAL mode来使用异步写入。
答案 2 :(得分:0)
尝试将INDEXE添加到您的数据库中:
CREATE INDEX IDXname ON player (name)