MENU

SQLite WAL 介绍

195979.jpg

在默认情况下 SQLite 的事务原子提交和回滚使用的是 rollback journal 模式。但是在 3.7.0 版本中 SQLite 引入了一种新的日志模式 Write-Ahead Log (常简写为 WAL )。与默认的日志模式相比,WAL 具有非常显著的优点:

  1. 在大部分应用场景下性能会更好。

  2. 更好的并发性能:读操作不会阻塞写操作,相应写操作也不会阻塞读操作。

  3. fsync() 调用更少,所以导致的阻塞次数也相应减少,磁盘 I/O 操作也相对更集中减少碎片化问题。

当然,WAL 也存在一些缺点:

  1. 所有的数据库操作必须都在同一台机器上进行,并且该机器的操作系统需要支持 VFS 特性。

  2. 当连接处于 WAL 模式中时我们无法修改页大小。

  3. 为满足 Wal 和相关共享内存的需要,使用 WAL 引入了两个额外的半持久性文件 -wal-shm 该文件需要占用一定的存储空间。

  4. 数据库读性能会比 rollback journal 模式略差 (大概慢 1% ~ 2% ),另外写操作也会间歇性的性能下降。

工作原理

默认的 rollback journal 模式工作原理大致为:写操作进行前进行数据库文件拷贝,然后对数据库进行写操作。如果发生 Crash 或者 rallback 则将日志中的原始内容回滚到数据库中进行恢复操作,否则在 Commit 完成时删除日志文件。

rollback.png

WAL 模式则采用了相反的做法。在进行数据库写操作时,它会先复制一份原始数据到日志文件中并且将写操作也更新到日志文件中而原有数据库内容则保存不变。如果事务失败,WAL 中的记录会被忽略;如果事务成功,它将在随后的某个时间被写回到数据库文件中二该步骤被称为 Checkpoint

wal.png

在读的时候,SQLite 将在 WAL 文件中搜索,找到最后一个写入点,记住它,并忽略在此之后的写入点(这保证了读写和读读可以并行执行);随后,它确定所要读的数据所在页是否在 WAL 文件中,如果在,则读 WAL 文件中的数据,如果不在,则直接读数据库文件中的数据。

性能相关

WAL 模式下写操作比 rollback journal 模式下更为集中,而且该模式下显著降低了磁盘同步的频率,所有相对来说写性能会更优秀。

与此相对,读操作的性能会出现部分下降,因为它需要额外对 -wal 文件进行一次检索。这意味着我们可能需要对 Checkpoint 的阈值(默认 1000 page)进行调整,另外 Checkpoint 本身就比较耗时且会对读操作进行阻塞。如果降低阈值大小则会导致 Checkpoint 变得频繁虽然提高了读性能,但是它又会影响写操作的性能指标。而且频繁的 Checkpoint 进行的同步操作也会大大增加数据库损坏的概率。因此我们应该基于真实场景通过大量实验测试来找到一个读写平衡的 Checkpoint 点。

标签: SQLite, WAL