pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
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,还可以实现 保存点,允许部分回滚 无效的事务操作(命令输错导致的 解析错误、插入重复的主键/唯一键等), 同时能够继续或提交事务在 出错之前所做的有效操作。目前, 任何错误都会使整个事务无效并 要求中止事务。
WAL 为数据库 在线备份和恢复(BAR)的 新方法提供了机会。要 使用这种方法,需要定期把数据 文件保存到另一块磁盘、磁带或另一台主机,并归档 WAL 日志文件。数据库文件副本和 归档的日志文件可以像 崩溃后恢复那样用于恢复。每次制作新的 数据库文件副本后,旧的日志 文件就可以删除。实现这一 功能需要记录数据文件和索引的创建 与删除;还需要开发一种 复制数据文件的方法(操作系统的复制命令 并不合适)。
实现这些收益的一个 障碍是它们需要在相当长的 时间内保存 WAL 条目(例如, 如果想要事务 UNDO,则需要保存 最长可能事务那么久)。目前的 WAL 格式极其庞大,因为它包含 许多磁盘页快照。目前这不算 严重问题,因为条目只需保存一两个 检查点间隔;但要获得这些未来的收益, 将需要某种压缩的 WAL 格式。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。