pg_stat_user_tables
和 pg_stat_user_objects
是PostgreSQL 中两个 非常重要的性能监控和统计视图。
核心概念
这两个视图都属于 PostgreSQL 的**统计收集器(Statistics Collector)**子系统。它们提供了关于数据库对象使用情况和性能的宝贵信息,是进行数据库性能分析、瓶颈排查和SQL调优的基石。
要确保这些视图中有数据,必须先确认 track_counts
参数是 on
的(默认通常是开启的)。
sql
SHOW track_counts;
1. pg_stat_user_tables
这个视图专门用于收集和显示当前数据库中用户定义表的统计信息。每个用户表对应一行记录。
主要字段详解
这些字段通常从最后一次重置统计信息(使用 pg_stat_reset()
)或者数据库启动开始累积。
字段名 | 类型 | 描述 |
---|---|---|
relid |
OID | 表的对象标识符(OID) |
schemaname |
name | 表所在的模式名(如 public ) |
relname |
name | 表的名字 |
seq_scan |
bigint | 在此表上发起的顺序扫描(全表扫描)的次数 |
seq_tup_read |
bigint | 顺序扫描读取的活元组(行)数(可能包含已删除但未清理的行) |
idx_scan |
bigint | 在此表上所有索引的索引扫描总次数 |
idx_tup_fetch |
bigint | 通过索引扫描读取的活元组数 |
n_tup_ins |
bigint | 插入的行数 |
n_tup_upd |
bigint | 更新的行数(包含HOT更新和不HOT更新) |
n_tup_del |
bigint | 删除的行数 |
n_tup_hot_upd |
bigint | HOT(仅堆元组)更新的行数。HOT更新是一种优化,避免更新索引。 |
n_live_tup |
bigint | 表中当前估算的活元组数(是估算值,非精确值) |
n_dead_tup |
bigint | 表中当前估算的死元组数(是估算值,是VACUUM的主要目标) |
n_mod_since_analyze |
bigint | 自上次分析(ANALYZE)以来插入、更新或删除的估算行数 |
last_vacuum |
timestamp | 最后一次手动或自动VACUUM此表的时间 |
last_autovacuum |
timestamp | 最后一次autovacuum守护进程清理此表的时间 |
last_analyze |
timestamp | 最后一次手动ANALYZE此表的时间 |
last_autoanalyze |
timestamp | 最后一次autoanalyze守护进程分析此表的时间 |
vacuum_count |
bigint | 此表被手动VACUUM的次数 |
autovacuum_count |
bigint | 此表被autovacuum进程清理的次数 |
analyze_count |
bigint | 此表被手动ANALYZE的次数 |
autoanalyze_count |
bigint | 此表被autoanalyze进程分析的次数 |
经典使用场景和查询示例
-
识别全表扫描过多的表
顺序扫描成本很高,特别是对大表。如果一个表频繁被全表扫描,应考虑为查询条件添加索引。
sqlSELECT schemaname, relname, seq_scan, seq_tup_read, seq_tup_read / NULLIF(seq_scan, 0) AS avg_tuples_per_scan FROM pg_stat_user_tables WHERE seq_scan > 0 ORDER BY seq_tup_read DESC LIMIT 10;
-
评估索引使用情况
检查哪些表"读多写少"但索引使用率却很低,这些表可能是添加索引的候选。
sqlSELECT schemaname, relname, seq_scan, idx_scan, n_tup_ins, n_tup_upd, n_tup_del, CASE WHEN (seq_scan + idx_scan) > 0 THEN (idx_scan * 100.0) / (seq_scan + idx_scan) ELSE 0 END AS idx_scan_pct FROM pg_stat_user_tables ORDER BY n_tup_ins + n_tup_upd + n_tup_del DESC; -- 按写入量排序
如果
idx_scan_pct
很低,但表读取量(seq_tup_read
)很高,说明查询可能没走索引。 -
监控死元组和自动清理状态
死元组过多会导致表膨胀、查询性能下降。这是监控autovacuum工作的核心视图。
sql
SELECT schemaname, relname,
n_live_tup, n_dead_tup,
(n_dead_tup * 100.0 / NULLIF((n_live_tup + n_dead_tup), 0)) AS dead_tup_ratio,
last_autovacuum, last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 10;
python
注:此SQL用了NULLIF函数,这是最简洁和高效避免报错ERROR:division by zero的方法:
- 在除数为零时返回 NULL
- 避免了除零错误
- 代码简洁易读
- NULLIF() 函数会在 (n_live_tup + n_dead_tup) 为零时返回 NULL,而任何数除以 NULL 都会返回 NULL,从而避免错误。
如果 dead_tup_ratio
过高且 last_autovacuum
是很久以前,可能需要调查autovacuum为何没有正常工作。
-
查看表的数据变更频率
sqlSELECT schemaname, relname, n_tup_ins AS inserts, n_tup_upd AS updates, n_tup_del AS deletes, (n_tup_ins + n_tup_upd + n_tup_del) AS total_changes FROM pg_stat_user_tables ORDER BY total_changes DESC LIMIT 10;
2. pg_stat_user_objects
有些PostgreSQL 版本不支持此视图
这个视图提供了更上层、更概括的统计信息,它涵盖了所有用户定义的对象(表、索引、序列、视图、物化视图等),但每个对象只有一行非常基础的统计信息。
主要字段详解
字段名 | 类型 | 描述 |
---|---|---|
relid |
OID | 对象的对象标识符(OID) |
schemaname |
name | 对象所在的模式名 |
relname |
name | 对象的名字 |
relkind |
char |
对象类型标识 : r = 普通表 i = 索引 S = 序列 v = 视图 m = 物化视图 c = 组合类型 t = TOAST表 f = 外表 |
relpages |
bigint | 磁盘上表示该关系的页数(尺寸的近似值,基于last vacuum 或analyze ) |
reltuples |
bigfloat | 表中的行数(尺寸的近似值,基于last vacuum 或analyze ) |
注意 :pg_stat_user_objects
没有 seq_scan
, n_tup_ins
等详细的I/O或DML统计信息。那些信息在更专门的视图里(如 pg_stat_user_tables
, pg_statio_user_indexes
)。
经典使用场景和查询示例
-
获取数据库中所有用户对象的大小估算
这是一个快速查看对象大小和行数的概览方法。
sqlSELECT schemaname, relname, CASE relkind WHEN 'r' THEN 'ordinary table' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' ELSE 'other' END AS object_type, pg_size_pretty(pg_relation_size(relid)) AS size, -- 更精确的大小 reltuples::bigint AS estimated_rows FROM pg_stat_user_objects ORDER BY pg_relation_size(relid) DESC;
-
查找最大的表和索引
sqlSELECT schemaname, relname, CASE WHEN relkind = 'i' THEN 'INDEX' ELSE 'TABLE' END AS type, pg_size_pretty(pg_relation_size(relid)) AS size FROM pg_stat_user_objects WHERE relkind IN ('r', 'i') -- 只查表和索引 ORDER BY pg_relation_size(relid) DESC LIMIT 20;
核心区别与联系
特性 | pg_stat_user_tables |
pg_stat_user_objects |
---|---|---|
范围 | 仅限用户表 | 所有用户对象(表、索引、序列、视图等) |
统计粒度 | 非常详细:包含扫描、读写、元组、 vacuum 等 | 非常基础:主要是对象类型和大小估算 |
主要用途 | 性能调优:查询分析、索引优化、Vacuum监控 | 对象管理:尺寸监控、对象清单浏览 |
关系 | 它是 pg_stat_user_objects 的一个子集和详细补充。 |
它是所有用户对象的一个概览目录。 |
重置统计信息
你可以使用以下函数重置统计信息(通常需要超级用户权限)。谨慎操作,因为这会使历史趋势数据丢失。
python
-- 重置当前数据库的所有统计信息
SELECT pg_stat_reset();
-- 重置单个表的统计信息
SELECT pg_stat_reset_single_table_counters(<table_oid>);
SELECT pg_stat_reset_single_function_counters(<function_oid>);
总结
- 当你需要深入分析表的访问模式、I/O性能、DML操作和Vacuum状态 时,使用
pg_stat_user_tables
。这是DBA进行日常性能诊断最常用的视图之一。 - 当你需要快速查看数据库中有哪些对象、它们的类型和大致大小 时,使用
pg_stat_user_objects
。它更像一个增强版的pg_class
视图,附带了一些统计信息。
通常,你会从 pg_stat_user_objects
找到一个感兴趣的大对象,然后通过它的 relid
和 relkind
去更专门的统计视图(如 pg_stat_user_tables
或 pg_statio_user_indexes
)中获取其详细性能数据。