SQL pg_stat_statements / MySQL performance_schema 的慢 SQL 捕获与分析模板

3次阅读

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。

SQL pg_stat_statements / MySQL performance_schema 的慢 SQL 捕获与分析模板

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';,若 ENABLEDNO,需执行: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 = ONsetup_instrumentsstatement/digest 启用才生成
  • MySQL 的 SUM_TIMER_WAIT 包含锁等待、IO 等全部耗时;PostgreSQL 的 total_exec_time 仅含执行器耗时,不含 parse/bind 时间(除非启用了 pg_stat_statements.trackall 模式)
  • 两者都默认不记录失败语句(如语法错误、权限拒绝),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 本身”,看不到“谁在调用”。

text=ZqhQzanResources