目标
每一次批量删除灾难的形状都相同:差一个运算符的 WHERE、放进单个事务、唯一的恢复手段是几小时前的备份。检查点模式把“勇气需求”从流程里拿掉:先把待删 id 落进草稿表、把选择当数据来评审、由该表驱动分批删除、并在签署确认前一直保留 id 清单。恢复路径从此是一条 INSERT SELECT,而不是一个周末。
步骤要点
- 用 CREATE TABLE AS 把符合保留策略的 id 落入检查点表并建唯一索引,此步对生产数据只读。
- 演练评审:统计检查点行数与被选行的 last_seen_at 上下界,确认 3000 万行与 18 个月口径吻合。
- 循环执行“CTE 取 5 万 id → DELETE 主表 → 删除检查点对应行”,剩余检查点行数即实时进度。
- 完成后先别删表:错误可凭检查点残余/归档一键 INSERT SELECT 恢复。
- pg_dump 导出检查点表留作审计记录,再 DROP 清理草稿 schema。
排错提示
运行期间又有新行符合谓词是正常的,检查点冻结了选择、正好避免追赶移动靶,下一轮再处理;批次越跑越慢多因外键逐行校验,可在窗口期 DEFERRABLE 化或先批量处理子表;检查点表堆积是草稿债,归档与 DROP 必须写进同一步骤。另外恢复路径只恢复行,不恢复已发出的下游事件,需与消费方协调。
适用边界
检查点会多付一次全表扫描与临时存储,极小规模清理用单个事务更简单;归档清单回答“删了什么”,但不回答外键约束重建等结构副作用。
代码示例
-- Stage first, delete later
CREATE TABLE purge_sessions_2026_10 AS
SELECT id FROM sessions
WHERE last_seen_at < now() - interval '18 months';
-- The batch loop consumes the checkpoint
WITH batch AS (SELECT id FROM purge_sessions_2026_10 LIMIT 50000)
DELETE FROM sessions WHERE id IN (SELECT id FROM batch);