作者: Vadim Mikheev 和 Oliver Elphick
预写式日志 (WAL) 是一种实现事务日志的标准方法.有关它的详细描述可以在 大多数(如果不是全部的话)有关事务处理的书中找到. 简而言之,WAL 的中心思想是对数据文件 的修改(它们是表和索引的载体)必须是只能发生在这些修改已经 记录了日志之后 -- 也就是说,在日志记录冲刷到永久存储器之后. 如果我们遵循这个过程,那么我们就不需要在每次事务提交的时候 都把数据页冲刷到磁盘,因为我们知道在出现崩溃的情况下, 我们可以用日志来恢复数据库:任何尚未附加到数据页的记录 都将先从日志记录中重做(这叫向前滚动恢复,也叫做 REDO) 然后那些未提交的事务做的修改将被从数据页中删除 (这叫向后滚动恢复 - UNDO).
使用 WAL 的第一个明显的好处就是显著地 减少了磁盘写的次数.因为在日志提交的时候只有日志文件需要冲刷到磁盘; 在多用户环境里,许多事务的提交可以用日志文件的一次 fsync() 来完成.而且,日志文件是顺序写的, 因此同步日志的开销要远比同步数据页的开销要小.
另外一个好处就是数据页的完整性.实际情况是,在 WAL 之前,PostgreSQL 从来不能保证 在崩溃的情况下数据页的完整性.在 WAL之前,在写的过程中的任何崩溃都可能导致:
索引记录指向一个不存在的表的行
索引记录在分裂操作中丢失
完全崩溃了的表和索引页的内容,因为数据页只写了一部分
索引的问题(问题 1 和 2)可能已经通过额外的 fsync() 调用修补好了,但是如果没有 WAL,那么没有很明显的 处理第三种情况的方法;WAL 在日志里保存整个 数据页的内容 -- 如果那些内容在崩溃后的恢复中需要确保数据页的完整性的话.
UNDO 操作还没有实现。 这就意味着由退出的事务做的修改将仍然占据磁盘空间, 因此我们仍然需要一个永久的 pg_clog 文件 保存事务的状态,因为我们不能回收事务标识符.一旦实现了 UNDO, 那么 pg_clog 就不再要求是永久的了; 我们就有可能在关闭的时候删除 pg_clog. (不过,这方面的紧迫性已经随着我们对 pg_clog 采取分段存储的方法而降低了 --- 我们不再需要永久保留 pg_clog 记录.)
有了 UNDO,我们还可能实现 savepoints, 这样就允许非法事务操作的部分回卷(因为误敲了命令导致的分析器错误, 插入了重复的主键/唯一键字等等)同时还能够继续或提交该事务在 发生错误之前的合法操作.目前,任何错误都将使整个事务成为非法并且 要求事务退出.
WAL 还提供了数据库在线备份和恢复 (backup and restore (BAR))的新方法. 要使用这个方法,我们可能要经常性地把数据文件保存到另外一个磁盘, 磁带或者另外一台主机并且还要备份 WAL 日志文件. 那么数据库文件拷贝和日志归档文件就可以用于象灾难恢复中那样 恢复数据.每次做完新数据库文件以后,这个老的日志文件就可以删除了. 实现这个设施可能需要记录数据文件和索引创建和删除的日志; 同时还需要开发一种方法来拷贝数据文件(操作系统拷贝命令是不合适的).
认识这些事情的好处的一个困难是它们要求在相当可观的时间段内 保存 WAL 日志(也就是说,如果需要事务的 UNDO, 那么和可能的最长的事务的时间一样长).目前的 WAL 格式的体积相当大,因为它包括多个磁盘页的镜像. 目前这还不是一个严重的问题,因为这些日志只需要保留一到两个 检查点的时间间隔;但是为了实现这些东西,以后我们可能需要某种压缩的 WAL 格式.