标准答案
- 更新和删除会留下旧 tuple 与可复用空洞,长事务或清理滞后会让表占用的物理空间持续增长;表膨胀不等同于业务行数增长。
- 索引会因为索引列更新、页分裂、删除后空洞和数据分布变化而膨胀;即使表本身不大,某个热点索引也可能成为 I/O 瓶颈。
- 排查要分别看 pg_relation_size、pg_indexes_size、索引扫描和命中率、dead tuples、写入模式和 vacuum 进度,不能只看数据库总大小。
- VACUUM 主要让空间可复用;REINDEX 或 REINDEX CONCURRENTLY 处理索引结构;表重写或 VACUUM FULL 可能回收文件空间,但锁、临时空间和失败恢复成本更高。
- 长期治理应缩短事务、让 autovacuum 跟上、删除低收益索引、降低不必要的索引列更新,并为历史数据设计归档或分区策略。
题目解析
“空间变大”只是现象,真正需要回答的是空间是否可复用、查询是否因此变慢,以及增长来自表版本、索引结构还是业务数据本身。
REINDEX CONCURRENTLY 可以降低对正常读写的阻塞,但会产生新索引、占用额外空间并增加 I/O;它不是无成本的在线修复。
修复后要确认对象大小、扫描计划、缓冲命中、写入放大和复制延迟是否改善。如果根因是长事务或无界写入,重建一次很快会再次膨胀。
常见误区
- 误区:发现对象变大就执行 VACUUM FULL。改正:先判断是否需要物理收缩文件,普通 VACUUM、索引重建或归档可能更安全。
- 误区:只重建索引,不处理长事务和 autovacuum。改正:结构重建只能处理当前结果,不能阻止旧版本继续堆积。
- 误区:把表大小增长全部当成数据增长。改正:同时比较 live/dead tuples、索引大小和历史写入量,区分业务增长与空间浪费。