检查点为 PostgreSQL 崩溃恢复建立一个可用起点。它同步这个检查点所需的数据文件变更,并记录相应恢复信息。依赖某段日志的数据页写出之前,相关 WAL 必须先持久化。这样的顺序让事务提交不必每次都把全部修改过的表页立即刷到磁盘;发生崩溃时,再从恢复起点重放后续必要变更。
坏掉的样子
检查点不是事务提交。数据页可以包含尚未提交事务写入的版本,读者究竟能看到哪些行,仍然由可见性与事务状态决定。检查点完成,不会把这些写入变成已提交,也不会把随手复制一份正在变化的数据目录变成有效基础备份。并发活动还可能再次弄脏页面,所以不能把完成提示理解成缓冲池从此全部干净。
日志保留也有别的限制。最大 WAL 大小是与自动检查点调度有关的软目标,不是磁盘使用硬上限;归档失败或复制槽保留,都可能让日志超过这个值。最小 WAL 大小则涉及回收并预留文件供以后复用,不是另一条强制触发检查点的阈值。如果理解错这些参数,可能一边看到检查点间隔正常,一边忽略实际上还在持续增长的归档积压。
快速验证
准备一台安静的 PostgreSQL 18 可丢弃实例,开启甲、乙两个全新的 psql -X -v ON_ERROR_STOP=1 会话。显式检查点和控制文件信息使用具有相应权限的管理角色。保留正常开启的同步落盘与同步提交设置。乙先创建计数器,并保存当前检查点位置:
SHOW fsync;
SHOW synchronous_commit;
CREATE SCHEMA checkpoint_demo;
CREATE TABLE checkpoint_demo.items (id integer PRIMARY KEY,n integer);
INSERT INTO checkpoint_demo.items VALUES (1,10);
CREATE TABLE checkpoint_demo.baseline AS
SELECT checkpoint_lsn FROM pg_control_checkpoint();
显示的两个设置都应为开启,初始已经提交的值是十。甲在一个保持打开的事务中把它改成九十九:
BEGIN;
UPDATE checkpoint_demo.items SET n=99 WHERE id=1 RETURNING n;
甲从自己的更新得到九十九,但此时不要提交。乙请求检查点,并查看普通读者可见的值:
CHECKPOINT;
SELECT c.checkpoint_lsn>b.checkpoint_lsn AS checkpoint_advanced,
(SELECT n FROM checkpoint_demo.items WHERE id=1) AS visible_value
FROM checkpoint_demo.baseline AS b CROSS JOIN pg_control_checkpoint() AS c;
检查点位置推进了,乙仍然读到十。维护工作已经完成,甲的事务却还没有决定提交还是回滚。这把数据库维护的进度与业务操作的提交状态明确区分开来,不能把其中一个完成信号当成另一个完成的证据。回到甲,核对自己的版本仍然可见,然后丢弃这次修改:
SELECT n FROM checkpoint_demo.items WHERE id=1;
ROLLBACK;
甲回滚前仍读到九十九。乙现在确认值恢复为原来的十,再完成一次普通提交,并在这次操作紧邻的位置记录前后检查点标识:
SELECT n FROM checkpoint_demo.items WHERE id=1;
UPDATE checkpoint_demo.baseline
SET checkpoint_lsn=(SELECT checkpoint_lsn FROM pg_control_checkpoint());
UPDATE checkpoint_demo.items SET n=11 WHERE id=1;
SELECT c.checkpoint_lsn=b.checkpoint_lsn AS no_new_checkpoint,
(SELECT n FROM checkpoint_demo.items WHERE id=1) AS committed_value
FROM checkpoint_demo.baseline AS b CROSS JOIN pg_control_checkpoint() AS c;
DO $$ BEGIN
IF (SELECT n FROM checkpoint_demo.items WHERE id=1) IS DISTINCT FROM 11 THEN
RAISE EXCEPTION 'checkpoint/transaction boundary result mismatch';
END IF;
END $$;
DROP SCHEMA checkpoint_demo CASCADE;
本次短调度的结果先是十,随后检查点未变化的比较为真,已经提交的值是十一。普通提交成功,并没有请求另一个检查点。在繁忙实例里,独立调度的检查点可能恰好改变这个比较结果,但不会改变提交本身的语义。断言核对最终行值,实验结束后删除自己的模式。
原演练报告的是事务可见性与检查点边界;本轮审阅没有重新执行双会话调度,没有测量恢复耗时,也没有模拟存储设备丢失已经确认写入的情况。持久性契约仍然依赖正确开启的相关设置,以及能够履行同步请求的存储。要判断实际恢复时间是否满足目标,需要另做基于真实保留工作量的崩溃恢复演练,不能从这几条查询完成得快直接推导出来。
同时考虑恢复与前台负载
延长检查点间隔,可能减少重复刷写,并在开启整页写入时减少一部分重复整页日志;崩溃后需要重放的工作也可能随之增加。检查点过于频繁,又可能提高日志和数据写流量,影响请求延迟。存储是快速本地磁盘,并不能单独证明更长的间隔就符合业务恢复目标,还是需要以测量作取舍。
完成目标参数把常规检查点工作分散到间隔中的某个比例,常用的九成是节奏目标,不是任何负载下都没有延迟尖峰的保证。应把检查点持续时间、请求触发与定时触发次数、日志增长和前台延迟结合起来看。累计计数应比较同一观察窗口内的增量,并检查 stats_reset;统计重置后数字变小,不代表工作量或故障已经改善。调小参数使任务更快完成,也可能意味着同一批写入挤在更短窗口里,不能只看完成时长缩短就认为代价下降。
在 PostgreSQL 18 中,检查点计数和写入、同步时间位于专门的检查点统计视图;后台写进程视图描述的是另一个组件。频繁由日志增长触发请求时,先判断是正常写入量、配置目标还是保留链路造成,再修改限额。最终应比较恢复测试和业务延迟,让调优结论对应实际达到的恢复能力,而不是只对应一个看起来整齐的参数值。
来源
- PostgreSQL 18 WAL 入门,预写顺序及无需立即刷出所有数据文件的提交持久性,已核验 2026-10-15。
- PostgreSQL 18 CHECKPOINT,显式检查点行为与所需权限,已核验 2026-10-15。
- PostgreSQL 18 WAL 配置,检查点调度、写入节奏和日志大小语义,已核验 2026-10-15。
- PostgreSQL 18 累计统计,专门的检查点统计视图,已核验 2026-10-15。