SQLite 优化实践


SQLite 的写入性能与磁盘的性能有很大的关系,例如在 SATA 上可能只有 100 左右,在 SSD 上大概有 1K 左右,如果直接使用 RAMDisk 测试能达到 1W 以上。除此之外,还可以通过一些方法进行相关的优化。

SQLite Execute Routine

修改配置

在介绍如何修改参数前,提前说明下相关的命令。

PRAGMA 语句是 SQLite 的扩展,主要用于修改数据库的配置等。

  1. 不同版本的特性可能会被删除或者新增,无法保证其兼容性。
  2. 未知的命令不会有错误消息出现,它只是简单的忽略。
  3. 有些 PRAGMA 只在 SQL 执行的部分阶段起作用,例如编译阶段sqlite3_prepare、执行阶段sqlite3_step

配置

可以通过 PRAGMA 命令查询或者设置当前系统的配置参数。

----- 要查询当前PRAGMA的值
sqlite> PRAGMA pragma_name;
----- 设置为新值
sqlite> PRAGMA pragma_name = value;

设置模式,可以是名称或等值的整数,但返回的值将始终是一个整数。

常用参数

主要包含了两个:A) synchronous 定义了何时写入磁盘;B) journal_mode 日志写入模式。

synchronous

sqlite> PRAGMA synchronous;
sqlite> PRAGMA synchronous = 2;

用于设置磁盘的写入时机。

  • 0/OFF 不进行同步设置,完全由操作系统进行控制;
  • 1/NORMAL V2默认设置,在关键操作后刷新磁盘,小几率导致数据库损坏;
  • 2/FULL V3默认设置,每次关键操作都会刷新磁盘,性能差但是可以保证数据库不损坏。

对于磁盘来说,此时的吞吐量会增加很多,1/2 差异不大。

journal_mode

控制日志文件如何存储和处理的日志模式,可以设置数据库级别。

其中 journal 为数据库事务提供 rollback 操作,当事务写入时,首先写入 journal 文件中,在提交时,根据 journal-mode 来处理 journal 日志文件。

若在提交之前由于断电等原因造成无法提交,当再次启动时,通过 journal 文档做回滚操作,保证数据库的完整性和一致性。

sqlite> PRAGMA journal_mode;
sqlite> PRAGMA journal_mode = mode;
sqlite> PRAGMA database.journal_mode;
sqlite> PRAGMA database.journal_mode = mode;

这里支持五种日志模式:

  • DELETE 默认,在事务结束时,日志文件将被删除;
  • WAL 使用 Write Ahead Log;
  • MEMORY 日志记录保留在内存中,而不是磁盘上,断电会丢失;
  • OFF 不保留任何日志记录;

关于 WAL

V3.7.0 版本支持,修改不直接写入数据库文件中,而是直接一个 WAL 的文件中,若事务失败,WAL 记录被忽略;若事务成功,随后在某个 checkpoint 时间点写回数据库。

此时读写、读读可完全并发执行,不会互相阻塞(写之间不能并发)。除了数据库文件,同时会增加 name.db-shm name.db-wal 两个文件。

为了避免读取的数据不一致,查询时也需要读取 WAL 文件,这样的代价就是读取会变得稍慢,但是写入会变快很多。要提高查询性能的话,可以减小 WAL 文件的大小,但写入性能也会降低。

另外,需要注意各个版本间的 WAL 可能不兼容,但是数据库文件是通用的。