我有一个在嵌入式Linux上运行的应用程序。 我有一个带有一些表的预构建DB,每个表都有很多行(数千)和52列。我提前构建了数据库,因为我担心如果我在运行时执行'INSERT',我将进行磁盘碎片,所以我首先使用大量垃圾'INSERT'并在运行时构建数据库我使用'UPDATE'。
我每隔3秒就向DB写入大量数据。为了使写入过程快速,我在SQLite中使用WAL模式。虽然,我有性能问题。似乎每当检查点发生时,它需要太长时间,处理器不能在不到3秒的时间内完成。 为了改善这一点,我创建了一个线程,在10次写入调用之后,它从主线程接收消息队列,而不是检查点。
所以现在,似乎情况更好但是WAL文件变得越来越大...... 我怎么在这里解决?
答案 0 :(得分:6)
为了避免碎片并且无需预先插入数据,您应该使用sqlite3_file_control()
和SQLITE_FCNTL_CHUNK_SIZE来设置块大小。以大块(例如,每次1MB)分配数据库文件空间应该减少文件系统碎片并提高性能。 Mozilla项目在{/ 3}}的Firefox / Thunderbird中为currently using this setting。
关于WAL。如果您经常编写大量数据,则应考虑将写入包装到更大的事务中。通常,每个INSERT都是自动提交的,SQLite必须等到数据真正刷新到磁盘或闪存 - 这显然非常慢。如果将多个写入包装到一个事务中,SQLite不必担心每一行,并且可以一次刷新多行,最有可能是单个闪存写入 - 这要快得多。 所以,如果可以的话,尝试将至少几百个写入包装到一个事务中。
根据我的经验,WAL on flash并没有真正起作用,我觉得坚持旧的日记模式更有利。例如,Android 4不为其SQLite数据库使用WAL模式,可能是有原因的。正如您所注意到的,在某些情况下,WAL有一种无限制增长的趋势(但是,如果交易很少发生,也会发生这种情况 - 所以请务必偶尔这样做。)
答案 1 :(得分:1)
在WAL模式下,SQLite将任何已更改的页面写入-wal
文件。
只有在检查点期间,这些页面才会写回数据库文件。
只有在没有并发读者的情况下才能截断-wal
文件。
您可以尝试使用SQLITE_CHECKPOINT_RESTART
或sqlite3_wal_checkpoint_v2
调用PRAGMA wal_checkpoint(RESTART)
来明确清除WAL文件,但如果有任何并发读者,则会失败。