pg_stat_statements 是什么
pg_stat_statements 是 PostgreSQL 的官方扩展,按归一化后的语句模板(常量被替换为占位符)累计调用次数、总执行时间、平均执行时间与扫描行数,是定位「哪条 SQL 吃掉了最多时间」的标准工具。它必须写在 shared_preload_libraries 中并重启实例,再执行 CREATE EXTENSION 才能查询。与慢查询日志相比,它给出的是全局累计视角,更适合找优化优先级。
基本信息
| 适用平台 | PostgreSQL 9.4+(字段名随版本变化) |
|---|---|
| 启用方式 | postgresql.conf 里 shared_preload_libraries = 'pg_stat_statements',重启后 CREATE EXTENSION |
| 版本差异 | PG13 起为 total_exec_time / mean_exec_time;更早版本是 total_time / mean_time |
| 统计口径 | 按归一化模板合并,同一模板不同常量合成一行 |
| 清零方式 | SELECT pg_stat_statements_reset(); |
典型使用场景
- 找出累计耗时最多的 SQL,确定优化顺序
- 压测前后对比:清零统计后跑同一负载,看变化幅度
- 定位应用里调用次数异常高的语句,判断是否有循环查询
- 验证索引优化的真实收益,而不是只看单次 EXPLAIN
- 与慢查询日志互补:日志看偶发尖峰,扩展看整体占比
启用与排名查询
启用与排名查询
# postgresql.conf 增加下面两行后重启实例
# shared_preload_libraries = 'pg_stat_statements'
# pg_stat_statements.max = 5000 # 最多跟踪的语句模板数
CREATE EXTENSION IF NOT EXISTS pg_stat_statements; -- 在目标数据库中执行
SELECT calls,
ROUND(total_exec_time::numeric, 1) AS total_ms,
ROUND(mean_exec_time::numeric, 2) AS mean_ms,
rows,
ROUND(100 * total_exec_time / SUM(total_exec_time) OVER (), 1) AS pct,
left(query, 60) AS query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;窗口管理与另一种排序
窗口管理与另一种排序
-- 压测或变更前清零,让统计数据只对应观察窗口
SELECT pg_stat_statements_reset();
-- 找「单次很慢」的语句:平均耗时排序,过滤掉样本太少的模板
SELECT calls, ROUND(mean_exec_time::numeric, 2) AS mean_ms, left(query, 60)
FROM pg_stat_statements
WHERE calls > 10
ORDER BY mean_exec_time DESC
LIMIT 10;关键列读法
| 列 | 含义 | 关注点 |
|---|---|---|
| calls | 模板被调用次数 | 高频小查询也会堆出很高的总耗时 |
| total_exec_time | 累计执行时间(毫秒) | 总时间榜首通常就是优化重点 |
| mean_exec_time | 平均执行时间 | 反映单次代价,需与 total 结合看 |
| rows | 返回或影响的累计行数 | 行数远超调用次数说明结果集偏大 |
| shared_blks_read / hit | 共享块物理读与命中次数 | 命中率低说明缓存不友好 |
如果查询结果为空,先确认扩展是否真的加载成功:改了配置没重启时 CREATE EXTENSION 会报找不到文件,可用 SELECT * FROM pg_available_extensions WHERE name = 'pg_stat_statements' 确认可用性。
视图里存的是归一化文本,常量已被替换为 $1 这类占位符,看不到具体参数值;要定位「哪个用户/哪批参数慢」,需结合 pg_stat_activity 或应用侧日志。