简体   繁体   English

提高SQLite的每秒UPDATE性能?

[英]Improve UPDATE-per-second performance of SQLite?

My question comes directly from this one, although I'm only interested on UPDATE and only that. 我的问题直接来自这个问题,虽然我只对UPDATE感兴趣并且只对此感兴趣。

I have an application written in C/C++ which makes heavy use of SQLite , mostly SELECT/UPDATE , on a very frequent interval (about 20 queries every 0.5 to 1 second) 我有一个用C/C++编写的应用程序,它在非常频繁的时间间隔内大量使用SQLite (主要是SELECT/UPDATE (每0.5到1秒约20次查询)

My database is not big, about 2500 records at the moments, here is the table structure: 我的数据库不大, 此刻约有2500条记录,这里是表结构:

CREATE TABLE player (
   id INTEGER PRIMARY KEY AUTOINCREMENT,
   name VARCHAR(64) UNIQUE,
   stats VARBINARY,
   rules VARBINARY
);

Up to this point I did not used transactions because I was improving the code and wanted stability rather performance. 到目前为止,我没有使用transactions因为我正在改进代码并希望稳定而不是性能。

Then I measured my database performance by merely executing 10 update queries, the following (in a loop of different values): 然后我通过仅执行10 update查询来测量我的数据库性能,以下(在不同值的循环中):

// 10 times execution of this
UPDATE player SET stats = ? WHERE (name = ?)

where stats is a JSON of exactly 150 characters and name is from 5-10 characters. 其中stats是一个恰好150个字符的JSON, name是5-10个字符。

Without transactions, the result is unacceptable: - about 1 full second (0.096 each) 没有交易,结果是不可接受的: - 大约1整秒(每个0.096)

With transactions, the time drops x7.5 times: - about 0.11 - 0.16 seconds (0.013 each) 随着交易,时间下降x7.5倍: - 约0.11 - 0.16秒(每个0.013)

I tried deleting a large part of the database and/or re-ordering / deleting columns to see if that changes anything but it did not. 我尝试删除数据库的大部分和/或重新排序/删除列,以查看是否有任何改变,但事实并非如此。 I get the above numbers even if the database contains just 100 records (tested). 即使数据库只包含100条记录 (已测试),我也会得到上述数字。

I then tried playing with PRAGMA options: 然后我尝试使用PRAGMA选项:

PRAGMA synchronous = NORMAL
PRAGMA journal_mode = MEMORY

Gave me smaller times but not always, more like about 0.08 - 0.14 seconds 给了我较小的时间但不总是,更像是0.08 - 0.14秒

PRAGMA synchronous = OFF
PRAGMA journal_mode = MEMORY

Finally gave me extremely small times about 0.002 - 0.003 seconds but I don't want to use it since my application saves the database every second and there's a high chance of corrupted database on OS / power failure. 最后给了我非常小的时间大约0.002 - 0.003秒,但我不想使用它,因为我的应用程序每秒保存数据库,并且很有可能在操作系统/电源故障时数据库损坏。

My C SQLite code for queries is: (comments/error handling/unrelated parts omitted) 我的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);

As you see, it's a pretty typical TABLE , records number is small and I'm doing a plain simple UPDATE exactly 10 times. 如你所见,它是一个非常典型的TABLE ,记录数量很小,而且我正在进行简单的简单UPDATE 10次​​。 Is there anything else I could do to decrease my UPDATE times? 我还能做些什么来减少我的UPDATE时间吗? I'm using the latest SQLite 3.16.2 . 我正在使用最新的SQLite 3.16.2

NOTE: The timings above are coming directly from a single END TRANSACTION query. 注意:上面的时间直接来自单个END TRANSACTION查询。 Queries are done into a simple transaction and i'm using a prepared statement. 查询是在一个简单的事务中完成的,我正在使用一个准备好的语句。

UPDATE: 更新:

I performed some tests with transaction enabled and disabled and various updates count. 我在执行启用和禁用事务以及各种更新计数时执行了一些测试。 I performed the tests with the following settings: 我使用以下设置执行测试:

VACUUM;
PRAGMA synchronous = NORMAL;  -- def: FULL
PRAGMA journal_mode = WAL;    -- def: DELETE
PRAGMA page_size = 4096;      -- def: 1024

The results follows: 结果如下:

no transactions (10 updates) 没有交易(10次更新)

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

no transactions (100 updates) 没有交易(100次更新)

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

no transactions (1000 updates) 没有交易(1000次更新)

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

with transactions (10 updates) 交易(10次更新)

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

with transactions (100 updates) 交易(100次更新)

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

with transactions (1000 updates) 交易(1000次更新)

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

My conclusions are that with transactions there's no sense in time cost per query . 我的结论是,对于transactionstime cost per query没有任何意义。 Perhaps the times gets bigger with colossal number of updates but i'm not interested in those numbers. 也许随着更新次数的增加,时代变得越来越大,但我对这些数字并不感兴趣。 There's literally no time cost difference between 10 and 1000 updates on a single transaction . 单个交易的10到1000次更新之间几乎没有时间成本差异。 However i'm wondering if this is a hardware limit on my machine and can't do much. 但是,我想知道这是否是我的机器上的硬件限制,并不能做太多。 It seems i cannot go below ~100 miliseconds using a single transaction and ranging 10-1000 updates, even by using WAL. 似乎我不能使用单个事务超过~100毫秒,并且即使使用WAL也可以进行10-1000次更新。

Without transactions there's a fixed time cost of around 0.025 seconds. 没有交易,固定时间成本约为0.025秒。

You may still be limited by the time it takes to commit a transaction. 您可能仍然受限于提交交易所需的时间。 In your first example each transaction took about 0.10 to complete which is pretty close to the transaction time for inserting 10 records. 在您的第一个示例中,每个事务大约需要0.10才能完成,这非常接近插入10条记录的事务时间。 What kind of results do you get if you batch 100 or 1000 updates in a single transaction? 如果您在单个交易中批量100或1000次更新,您会得到什么样的结果?

Also, SQLite expects around 60 transactions per second on an average hard drive, while you're only getting about 10. Could your disk performance be the issue here? 此外,SQLite预计平均硬盘驱动器每秒大约有60个事务处理,而你只能得到10个左右。这可能是你的磁盘性能问题吗?

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

With such small amounts of data, the time for the database operation itself is insignificant; 由于数据量很小,数据库操作本身的时间是微不足道的; what you're measuring is the transaction overhead (the time needed to force the write to the disk), which depends on the OS, the file system, and the hardware. 您测量的是事务开销(强制写入磁盘所需的时间),这取决于操作系统,文件系统和硬件。

If you can live with its restrictions (mostly, no network), you can use asynchronous writes by enabling WAL mode . 如果您可以忍受其限制(主要是没有网络),则可以通过启用WAL模式来使用异步写入。

尝试将INDEXE添加到您的数据库:

CREATE INDEX IDXname ON player (name)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM