预写式日志 (WAL) 是一种实现事务日志的标准方法。有关它的详细描述可以在大多数(如果不是全部的话)有关事务处理的书中找到。 简而言之,WAL 的中心思想是对数据文件的修改(它们是表和索引的载体)必须是只能发生在这些修改已经记录了日志之后, 也就是说,在日志记录冲刷到永久存储器之后。 如果我们遵循这个过程,那么我们就不需要在每次事务提交的时候都把数据页冲刷到磁盘,因为我们知道在出现崩溃的情况下, 我们可以用日志来恢复数据库: 任何尚未附加到数据页的记录都将先从日志记录中重做(这叫向前滚动恢复,也叫做 REDO)然后那些未提交的事务做的修改将被从数据页中删除(这叫向后滚动恢复,UNDO)。
使用 WAL 的第一个明显的好处就是显著地减少了磁盘写的次数。 因为在日志提交的时候只有日志文件需要冲刷到磁盘; 在多用户环境里,许多事务的提交可以用日志文件的一次 fsync() 来完成。而且,日志文件是顺序写的, 因此同步日志的开销要远比同步数据页的开销要小。
另外一个好处就是数据页的完整性。实际情况是,在 WAL 之前,PostgreSQL 从来不能保证在崩溃的情况下数据页的完整性。 在 WAL 之前,在写的过程中的任何崩溃都可能导致:
索引记录指向一个不存在的表的行
索引记录在分裂操作中丢失
完全崩溃了的表和索引页的内容,因为数据页只写了一部分
索引的问题(问题 1 和 2)可能已经通过额外的 fsync() 调用修补好了,但是如果没有 WAL,那么没有很明显的处理第三种情况的方法; WAL 在日志里保存整个数据页的内容 -- 如果那些内容在崩溃后的恢复中需要确保数据页的完整性的话。