在数据库长期运行过程中,表膨胀与索引膨胀是 KingbaseES(KES)DBA 最常面对的隐形杀手。它们悄无声息地蚕食磁盘空间、拖慢查询性能,严重时甚至威胁系统稳定性。本文从索引重建、垃圾回收原理、长事务阻断、autovacuum 精细化调优四个维度,系统梳理 KES 资源回收的核心机制与实战方法。
一、REINDEX CONCURRENTLY:不停机重建膨胀索引
随着业务 DML 语句持续增长,索引会像表一样发生膨胀。膨胀的索引不仅浪费磁盘空间,还会显著降低查询性能——新构建的索引往往比反复更新的旧索引提供更好的访问效率。
为什么不能直接用 REINDEX?
普通 REINDEX 命令需要 ACCESS EXCLUSIVE 锁,这是最高级别的锁,会阻塞一切业务语句,生产环境中几乎不可接受。
解决方案是使用 REINDEX ... CONCURRENTLY,其锁级别降为 SHARE UPDATE EXCLUSIVE,不阻塞 DML 操作,实现业务无感知的索引重建。
REINDEX CONCURRENTLY 的六个执行阶段
| 阶段 | 操作内容 | 关键说明 |
|---|---|---|
| ① 创建新索引 | 生成临时索引,命名以 idx_ccnew 开头 | 此时新索引为空,尚未包含数据 |
| ② 构建新索引 | 全表扫描,填充新索引内容 | 期间新写入数据同步进入新索引 |
| ③ 验证新索引 | 将构建阶段新插入的数据补充进索引 | 类似 CREATE INDEX CONCURRENTLY 的逻辑 |
| ④ 交换索引 | 新旧索引互换,旧索引标记为 invalid | 业务流量切换至新索引 |
| ⑤ 标记旧索引为 dead | indislive、indisready、indisvalid 均置为 false | 旧索引彻底退出服务 |
| ⑥ 删除旧索引 | 物理清除旧索引占用的磁盘空间 | 完成整个重建流程 |
识别异常残留的无效索引
如果 REINDEX CONCURRENTLY 中途失败,可能留下名称含 _ccnew 的无效索引,需及时清理:
SELECT c.relname AS index_name, sys_size_pretty(sys_relation_size(c.oid))
FROM sys_index i JOIN sys_class c ON i.indexrelid = c.oid
WHERE c.relname LIKE '%_ccnew' -- 重建过程产生的临时索引
AND NOT indisvalid -- 处于 INVALID 状态
LIMIT 10;


