
PostgreSQL 19 还在 Beta(Beta 2 已在 2026-07 放出),但有一项改动足够让 DBA 提前做实验环境:内核里的 REPACK / REPACK CONCURRENTLY。以前表膨胀到难看,要么 VACUUM FULL 硬锁,要么上 pg_repack 扩展并和版本、权限、复制槽共舞。现在主流路径开始收回 core。
和并行 autovacuum、分区 merge/split、SQL/PGQ 相比,REPACK 更“运维日常”。膨胀不浪漫,但会真实吃磁盘、拖指数扫描、让自动清理永远赶不上。
膨胀从哪来,为何 FULL 不受欢迎
更新多的表(会话、任务队列、状态机)容易留下死元组。VACUUM 通常标记可复用空间,不一定把文件缩回操作系统。于是你看到:pg_total_relation_size 很大,活行不多,备份和缓存却更沉。
VACUUM FULL / CLUSTER 能重建瘦身,代价是长时间强锁,业务写入卡死。pg_repack 的思路是:旁路建一份紧凑拷贝,追增量,再短锁切换。PG19 把这套能力收进 SQL 命令语义(Beta 阶段细节仍可能微调,上线前以正式发行说明为准):
-- 概念用法:在线重建,避免长时间 exclusive lock
REPACK orders CONCURRENTLY;
读官方解读时,把它理解成“受支持的在线重写”,而不是新的日常 VACUUM 替代品。
CONCURRENTLY 在买什么
你买的是 锁持有时间的形态变化:重建过程中读写仍走旧副本,切换窗口尽量短。它不是零代价:
- 重建期间多一份表体积峰值(旧 + 新);
- CPU、IO、WAL 都会抬升;
- 长事务、残双打、未熟的 DDL 仍可能卡住最终换发;
- 逻辑复制、订阅端、依赖物理地址假设的外部工具要回归。
若磁盘只剩 10% 就点 REPACK CONCURRENTLY,你可能在救膨胀的路上先把盘写满。先看空间,再看锁。
图:在线重写——旧页与新页短暂并存

和并行 autovacuum 怎么分工
PG19 让 autovacuum 在索引清理等路径上更好用并行(autovacuum_max_parallel_workers 等参数,以发行说明为准)。它解决的是 日常垃圾回收跟不跟得上;REPACK 解决的是 文件已经胖到需要重写。
粗粒度策略:
- 先观测:死元组比例、年龄、
n_dead_tup、索引 bloat 估计、autovacuum 是否频繁跳票。 - 先调自动清理:scale factor、阈值、IO 限制、是否被长事务钉住。
- 仍系统性偏胖:维护窗口或低峰
REPACK CONCURRENTLY;热点大表单独排期。 - 扩展:若你仍停在 16–18,继续
pg_repack,但把切换到 19 后的演练写进 runbook。
不要把 REPACK 当“每次发布后的仪式”。重写越勤,IO 账单越高,切换风险窗口越多。
上线前我会列的检查单
空间与负载
- 目标表 + 索引大小 × 2 是否放得下;
- WAL 盘与归档是否跟得上峰值;
- 是否与全量备份、大批量 ETL 撞车。
会话与锁
- 有无小时级空闲事务;
- 切换前后是否要暂停危险 DDL;
statement_timeout/ 维护窗口是否够一次失败重试。
复制与周边
- 流复制延迟在重建期的可接受阈值;
- 逻辑复制 publication 是否覆盖相关表,订阅端冲突怎么处理;
- 依赖
ctid或物理顺序的脚本(少见但致命)清掉。
应用侧
- 连接池是否会在短阻塞时雪崩重试;
- 重试是否幂等;
- 大事务是否能拆批(REPACK 救不了“单事务更新整表”的设计)。
和 SQL/PGQ 的一点关系
同版本宣传的 SQL/PGQ 让你在关系表上跑属性图查询。图查询本身不制造膨胀,但若因此多了大量边表写入、频繁改点查边,写放大会把你更快推到 REPACK 场景。新查询能力上线时,顺手把边表的 vacuum / 统计信息 / 填充因子看一眼,比事后救火便宜。
小结
PG19 的 REPACK 是在说:表重写是内核级运维能力,不再默认外包给扩展。真正省事的是 runbook——何时该 REPACK、何时该先杀长事务、何时其实只是索引设计有问题。Beta 期适合在预发用真实比例的数据量跑一遍,量峰值空间和切换抖动,而不是在生产第一次手滑执行。膨胀会一直在;你要的是可控的瘦身,不是更酷的 SQL 关键字。


