pgstattuple 返回 pagetotal、pageused、pagefree、deadtuplecount 和 deadtuplelen 五个关键膨胀指标,其中 pagefree 占比和 deadtuplecount 增长趋势直接反映表膨胀程度。

pgstattuple 函数返回哪些关键膨胀指标
pgstattuple 是 PostgreSQL 提供的系统函数,用于返回表或索引的物理存储细节。它不直接说“膨胀了”,而是给出几个核心数值:占用页数(pagetotal)、实际存数据的页数(pageused)、空闲页数(pagefree)、死亡元组数(deadtuplecount)和死亡元组所占字节(deadtuplelen)。真正反映膨胀程度的是 pagefree 占比和 deadtuplecount 是否持续增长——比如某表 pagetotal=10000 但 pageused=3000,说明近 70% 页面是空的,大概率需要 VACUUM 或 VACUUM FULL。
如何对单个表运行 pgstattuple 并解读结果
确保已加载 pgstattuple 扩展(CREATE EXTENSION IF NOT EXISTS pgstattuple;),然后执行:
SELECT * FROM pgstattuple('public.orders');重点关注以下几项:
-
deadtuplecount > 0且近期写入频繁 → 可能存在未清理的死亡元组 -
pagefree > pagetotal * 0.2(即空闲空间超 20%)→ 物理膨胀较明显 -
avg_dead_tuple_len > 0且值较大 → 死亡元组体积不小,单纯VACUUM可能无法回收全部空间(需VACUUM FULL或CLUSTER) -
free_percent字段(部分版本提供)若 > 25%,基本可判定需干预
索引膨胀怎么查?用 pgstatindex 替代 pgstattuple
pgstattuple 不适用于索引;查索引得用 pgstatindex。它返回类似结构,但关注点不同:
-
index_size是索引总大小,used_size是实际被键值使用的字节数 -
leaf_fragmentation> 15% 表示叶页碎片严重,查询性能可能下降 -
avg_leaf_density过低(如 - 执行:
SELECT * FROM pgstatindex('orders_user_id_idx');
注意:B-tree 索引膨胀后,VACUUM 对其无效,必须用 REINDEX 或 CREATE INDEX CONCURRENTLY 替换。
为什么 pgstattuple 结果有时不准或报错
常见原因包括:
- 用户无目标表的
SELECT权限 → 报错permission denied for table xxx,需先授予权限或切到超级用户 - 表正被长时间持有
ACCESS EXCLUSIVE锁(如大事务、ALTER TABLE)→pgstattuple会卡住或超时,建议避开业务高峰执行 - 在只读备库上执行 → 返回错误
cannot execute pgstattuple in a read-only transaction,必须在主库查 - 对分区表主表调用 → 返回的是主表自身的元数据(不含子表),要查每个子表单独执行,例如
pgstattuple('orders_2024_q1')
真实生产中,膨胀往往不是单次查询能定论的,得结合 pg_stat_all_tables 的 n_dead_tup 和历史趋势一起看——比如连续三天 n_dead_tup 增长 50 万,但 last_vacuum 是一周前,那问题就比较明确了。










