postgres中表占用的空间都很小,但是库占用空间却很大,问题定位
·
这个现象很典型 :单个表看上去都不大,但整个库(database)占用空间却很大。在 PostgreSQL 里通常有几类可能原因,可以一步步排查。
1. 库大小包含的内容
数据库大小 =
- 表数据 + 索引
- TOAST 表(大字段存储)
- 系统表
- 膨胀空间(dead tuples,还没 vacuum full 回收)
- 其他对象(临时表、未清理的表)
所以只查 pg_statio_user_tables 的表大小,可能漏掉不少东西。
2. 排查步骤
✅ 步骤 1:确认数据库大小
SELECT pg_size_pretty(pg_database_size(current_database()));
✅ 步骤 2:查看库里所有对象(表+索引+toast)
SELECT
nspname AS schema_name,
relname AS object_name,
relkind,
pg_size_pretty(pg_total_relation_size(pg_class.oid)) AS total_size
FROM pg_class
JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE relkind IN ('r','i','t') -- r=表, i=索引, t=TOAST表
ORDER BY pg_total_relation_size(pg_class.oid) DESC;
这样能看到:
- 哪些索引很大
- 哪些 TOAST 表占了很多空间
✅ 步骤 3:检查是否有膨胀 (bloat)
表和索引可能被更新/删除过很多次,导致文件很大,但有效数据很少。
SELECT
schemaname, relname,
n_live_tup, n_dead_tup
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;
n_dead_tup很大说明有很多“死元组”,需要VACUUM FULL或重建索引。
✅ 步骤 4:检查临时对象
有时候应用产生了临时表/临时索引没清理。
SELECT nspname, relname
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE nspname LIKE 'pg_temp%';
✅ 步骤 5:确认是不是 WAL / 系统目录占用
数据库大小(pg_database_size)只算 base/DBOID/,不包括 pg_wal。
所以如果 du -sh $PGDATA 看到很大,但 pg_database_size() 很小,多半是 WAL 没清理(归档/复制没跑通)。
3. 解决思路
- 如果是 索引太大 →
REINDEX TABLE xxx; - 如果是 TOAST 占用 → 检查大字段,是否需要清理或分离存储
- 如果是 膨胀 →
VACUUM FULL或CLUSTER重写表 - 如果是 临时表 → 清理掉
- 如果是 WAL → 检查归档/复制是否正常
更多推荐
所有评论(0)