7

我有一个在嵌入式 linux 上运行的应用程序。我有一个预先构建的数据库,其中包含一些表,每个表都有很多行(数千)和 52 列。我提前构建了数据库,因为我担心如果我将在运行时执行“插入”,我会产生磁盘碎片,所以我首先构建一个带有大量垃圾“插入”的数据库,并在运行时我使用“更新”。

我每 3 秒向数据库写入大量数据,为了加快写入过程,我在 SQLite 中使用 WAL 模式。虽然,我有性能问题。似乎每当一个检查点发生时,它花费的时间太长,处理器无法在不到 3 秒的时间内完成。为了改进这一点,我创建了一个线程,在大约 10 次写入调用之后,它从主线程接收消息队列,而不是检查点。

所以现在,情况似乎好转了,但 WAL 文件越来越大......我该如何解决?

4

2 回答 2

7

为避免碎片化并消除预插入数据的需要,您应该使用sqlite3_file_control()SQLITE_FCNTL_CHUNK_SIZE设置块大小。以大块(比如一次 1MB)分配数据库文件空间,应该可以减少文件系统碎片并提高性能。Mozilla 项目目前在 Firefox/Thunderbird 中使用此设置并取得了巨大成功

关于WAL。如果您经常写入大量数据,则应考虑将写入包装到更大的事务中。通常,每个 INSERT 都是自动提交的,SQLite 必须等到数据真正刷新到磁盘或闪存——这显然非常慢。如果您将多个写入包装到一个事务中,SQLite 不必担心每一行,并且可以一次刷新多行,很可能是单个闪存写入 - 这要快得多。因此,如果可以,请尝试将至少几百个写入包装到一个事务中。

根据我的经验,Flash 上的 WAL 并不能很好地工作,我发现坚持旧的日志模式更有益。例如,Android 4 的 SQLite 数据库不使用 WAL 模式,这可能是有原因的。正如您所注意到的,WAL 在某些情况下有无限增长的趋势(但是,如果很少提交事务也会发生这种情况 - 所以一定要偶尔这样做)。

于 2012-11-19T09:32:53.953 回答
2

在 WAL 模式下,SQLite 将任何更改的页面写入-wal文件。只有在检查点期间,这些页面才会写回数据库文件。

-wal只有在没有任何并发​​阅读器时才能截断文件。

sqlite3_wal_checkpoint_v2您可以尝试通过调用withSQLITE_CHECKPOINT_RESTART或execution 来显式清除 WAL 文件PRAGMA wal_checkpoint(RESTART),但如果有任何并发​​读取器,这将失败。

于 2012-11-15T10:14:37.883 回答