PgSQL中pg_stat_user_tables 和 pg_stat_user_objects参数详解
pg_stat_user_tables
和 pg_stat_user_objects
是PostgreSQL 中两个 非常重要的性能监控和统计视图。
核心概念
这两个视图都属于 PostgreSQL 的**统计收集器(Statistics Collector)**子系统。它们提供了关于数据库对象使用情况和性能的宝贵信息,是进行数据库性能分析、瓶颈排查和SQL调优的基石。
要确保这些视图中有数据,必须先确认 track_counts
参数是 on
的(默认通常是开启的)。
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进程分析的次数 |
经典使用场景和查询示例
-
识别全表扫描过多的表
顺序扫描成本很高,特别是对大表。如果一个表频繁被全表扫描,应考虑为查询条件添加索引。SELECT 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;
-
评估索引使用情况
检查哪些表“读多写少”但索引使用率却很低,这些表可能是添加索引的候选。SELECT schemaname, relname, seq_scan, idx_scan,n_tup_ins, n_tup_upd, n_tup_del,CASE WHEN (seq_scan + idx_scan) > 0THEN (idx_scan * 100.0) / (seq_scan + idx_scan)ELSE 0END 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工作的核心视图。
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;
注:此SQL用了NULLIF函数,这是最简洁和高效避免报错ERROR:division by zero的方法:
- 在除数为零时返回 NULL
- 避免了除零错误
- 代码简洁易读
- NULLIF() 函数会在 (n_live_tup + n_dead_tup) 为零时返回 NULL,而任何数除以 NULL 都会返回 NULL,从而避免错误。
SQL报错解决方案链接:https://blog.csdn.net/liumangtuzi888/article/details/151362257?sharetype=blogdetail&sharerId=151362257&sharerefer=PC&sharesource=liumangtuzi888&spm=1011.2480.3001.8118
如果 dead_tup_ratio
过高且 last_autovacuum
是很久以前,可能需要调查autovacuum为何没有正常工作。
- 查看表的数据变更频率
SELECT 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
)。
经典使用场景和查询示例
-
获取数据库中所有用户对象的大小估算
这是一个快速查看对象大小和行数的概览方法。SELECT schemaname,relname,CASE relkindWHEN '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;
-
查找最大的表和索引
SELECT 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 的一个子集和详细补充。 | 它是所有用户对象的一个概览目录。 |
重置统计信息
你可以使用以下函数重置统计信息(通常需要超级用户权限)。谨慎操作,因为这会使历史趋势数据丢失。
-- 重置当前数据库的所有统计信息
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
)中获取其详细性能数据。