pg_stat_statements需先在postgresql.conf中配置shared_preload_libraries并重启,再执行create extension;查最慢10条sql:select query, total_exec_time, calls, mean_exec_time from pg_stat_statements order by total_exec_time desc limit 10。

pg_stat_statements 怎么开启并查出最慢的 10 条 SQL?
PostgreSQL 默认不启用 pg_stat_statements,必须手动加载扩展并重启或重载配置。它不是“开箱即用”的监控功能,漏掉这步就永远看不到执行统计。
实操建议:
- 确认已安装扩展:
SELECT * FROM pg_available_extensions WHERE name = 'pg_stat_statements'; - 在
postgresql.conf中添加:shared_preload_libraries = 'pg_stat_statements'(注意:必须是 shared_preload_libraries,不是其他配置项) - 重启 PostgreSQL(
pg_ctl restart或 systemctl),仅 reload 不生效 - 连接后创建扩展:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements; - 查最慢 SQL:
SELECT query, total_exec_time, calls, mean_exec_time FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;
常见错误现象:查询返回空或只有极简语句——大概率是没重启,或者用户没有 pg_read_all_stats 权限(普通用户需显式授权)。
performance_schema 在 MySQL 里为什么查不到慢 SQL?
MySQL 的 performance_schema 默认不采集 SQL 文本,只记录事件骨架;即使开了,events_statements_history_long 表也默认关闭采集,且不按“执行时间”自动过滤。
实操建议:
- 检查是否启用语句采集:
SELECT * FROM performance_schema.setup_consumers WHERE NAME = 'events_statements_history_long';,若ENABLED是NO,需执行:UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_history_long'; - 确保采集器开启:
SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE 'statement/%' AND ENABLED = 'NO' LIMIT 5;,批量启用:UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'statement/sql/%'; - 查最近慢语句(比如 >1s):
SELECT DIGEST_TEXT, SUM_TIMER_WAIT/1000000000000 AS time_s, COUNT_STAR FROM performance_schema.events_statements_summary_by_digest WHERE SUM_TIMER_WAIT > 1000000000000 ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;
性能影响:开启全量 statement 采集会增加约 5–10% CPU 开销,生产环境建议只在排查期临时启用,避免长期开着 events_statements_history_long(它吃内存)。
pg_stat_statements 和 performance_schema 的结果为什么对不上?
两者统计口径根本不同:pg_stat_statements 统计的是归一化后的“查询模板”(比如 SELECT * FROM users WHERE id = $1),而 performance_schema 默认按原始文本或 DIGEST 分组,且 DIGEST 计算方式依赖 performance_schema_digests_size 和字符集处理逻辑。
关键差异点:
-
pg_stat_statements自动参数化,忽略字面值;performance_schema的 DIGEST 需要performance_schema = ON且setup_instruments中statement/digest启用才生成 - MySQL 的
SUM_TIMER_WAIT包含锁等待、IO 等全部耗时;PostgreSQL 的total_exec_time仅含执行器耗时,不含 parse/bind 时间(除非启用了pg_stat_statements.track的all模式) - 两者都默认不记录失败语句(如语法错误、权限拒绝),
pg_stat_statements需设pg_stat_statements.track_utility = on才捕获EXPLAIN类命令
一个典型坑:用 SHOW PROCESSLIST 看到某条 SQL 正在跑很久,但 performance_schema 里找不到——因为它还没执行完,而 events_statements_history_long 只存已完成事件。
怎么把慢 SQL 快速导出成可分析的格式?
直接从视图查出来复制粘贴容易丢格式、混乱参数、漏上下文。真正能用于后续分析(比如丢给 DBA 或压测工具)的输出,得带执行计划、绑定变量、时间戳和库名。
实操建议:
- PostgreSQL:用
EXPLAIN (ANALYZE, BUFFERS)套查到的慢 query(注意替换占位符为实际值),例如:EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE created_at > '2024-01-01'; - MySQL:先查
DIGEST,再用SELECT * FROM performance_schema.events_statements_history_long WHERE DIGEST = 'xxx'\G拿完整原始语句和TIMER_START - 统一建议:加时间范围过滤,避免拉全表。pg_stat_statements 可用
WHERE last_call > now() - interval '1 hour';performance_schema 可用WHERE EVENT_TIME > DATE_SUB(NOW(), INTERVAL 1 HOUR) - 别信“平均耗时”,重点看
stddev_exec_time(pg)或MAX_TIMER_WAIT(MySQL)——抖动大的 SQL,往往比均值高但稳定的问题更危险
最容易被忽略的一点:两个系统都不保存客户端 IP、应用名、事务 ID。想定位到具体服务实例,得靠应用层打日志或代理层(如 pgbouncer / ProxySQL)补字段。光靠数据库原生视图,永远只能看到“SQL 本身”,看不到“谁在调用”。










