我有一个在embedded式Linux上运行的应用程序。 我有一个预先build立的DB与一些表,其中每个有很多行(千)和52列。 我build立了数据库前面,因为我担心,如果我会做'插入'在运行时,我会做磁盘碎片,所以而是我build立一个数据库首先有很多垃圾'插入',在运行时我使用“更新”。
我每隔3秒向DB写入大量数据,而为了使写入过程更快,我在SQLite中使用了WAL模式。 虽然,我有一个performance的问题。 似乎每当检查点发生时,它花费的时间太长,处理器不能在less于3秒的时间内完成。 为了改善这一点,我创build了一个线程,在10个写入调用之后,它从主线程接收一个消息队列,而不是检查点。
所以现在看起来情况好多了,但是WAL文件越来越大了……我怎么在这里工作?
为了避免碎片并且不需要预先插入数据,您应该使用带有SQLITE_FCNTL_CHUNK_SIZE的 sqlite3_file_control()
来设置块大小。 以大块(一次为1MB)分配数据库文件空间应减少文件系统碎片并提高性能。 Mozilla项目目前在Firefox / Thunderbird中使用这个设置 取得了巨大的成功 。
关于WAL。 如果你经常写很多数据,你应该考虑把你的写入包装成更大的事务。 通常情况下,每个INSERT都是自动提交的,SQLite必须等到数据真正刷新到磁盘或闪存 – 这显然非常慢。 如果将多个写入包装到一个事务中,SQLite不需要担心每一行,并且可以同时刷新多行,最有可能的是写入单个闪存 – 这要快得多。 所以,如果可以的话,尽量把至少几百个写入包装到一个事务中。
根据我的经验,WAL上的闪光灯效果不是很好,而且我发现坚持旧的日记模式更有利。 例如,Android 4的SQLite数据库不使用WAL模式,可能是有原因的。 正如你所注意到的,WAL在某些情况下有一定的增长势头(但是,如果事务很少发生,也会发生,所以一定要偶尔做)。
在WAL模式下,SQLite将所有更改的页面写入-wal
文件。 只有在检查点期间才会将这些页面写回到数据库文件中。
-wal
文件只能在没有任何并发读取器的情况下才能被截断。
您可以尝试通过使用SQLITE_CHECKPOINT_RESTART
调用sqlite3_wal_checkpoint_v2
或执行PRAGMA wal_checkpoint(RESTART)
来清除WAL文件,但是如果有任何并发读取器,则会失败。