17370845950

SQL 慢查询日志开启后如何快速定位高频 SQL
用 mysqldumpslow -s c -t 20 日志路径按执行次数排序取前20,它自动归一化参数识别模板级高频SQL;PostgreSQL则通过 pg_stat_statements 扩展查 calls 字段排序。

MySQL 慢查询日志里怎么筛出执行次数最多的 SQL?

慢查询日志(slow_query_log)默认只记录耗时超阈值的语句,不自带频次统计。想快速定位“高频 SQL”,得靠后处理:先确保日志格式支持解析,再用命令行工具聚合。

  • 确保 log_output 设为 FILETABLE(推荐 FILE,便于用 mysqldumpslowawk 处理)
  • 开启 long_query_time = 0 可捕获所有查询(仅限调试,线上慎用)
  • 若用 log_output = TABLE,数据存在 mysql.slow_log 表,但默认不索引 sql_textGROUP BY 效率低

常用做法是导出日志文件后用 mysqldumpslow

mysqldumpslow -s c -t 20 /var/lib/mysql/slow.log

其中 -s c 表示按执行次数排序,-t 20 取前 20 条。注意:它会自动归一化参数(如把 WHERE id = 123WHERE id = 456 视为同一条),适合识别模板级高频语句。

PostgreSQL 的 pg_stat_statements 怎么查调用最频繁的 SQL?

PostgreSQL 不依赖文本日志,而是靠扩展 pg_stat_statements 实时统计。它天然记录 calls(执行次数)、total_timemean_time 等字段,查高频 SQL 更直接。

  • 需先在 postgresql.conf 中启用:shared_preload_libraries = 'pg_stat_statements',并重启
  • 执行 CREATE EXTENSION pg_stat_statements;
  • 查询示例:
    SELECT calls, total_time, query FROM pg_stat_statements ORDER BY calls DESC LIMIT 10;

注意三点:

  • query 字段是归一化后的语句(常量被 $1 替代),和实际日志里的原始 SQL 不完全一致
  • 默认只跟踪 top-N 查询(由 pg_stat_statements.max 控制,建议设为 10000+)
  • 数据不清零,长期运行后可能掩盖近期突增的高频语句,可定期用 pg_stat_statements_reset() 清空重计

为什么用正则或 grep 直接扫慢日志容易漏掉高频 SQL?

直接对 MySQL 慢查询日志做 grepawk '{print $NF}' 是常见误区,问题在于:

  • 日志每条记录包含多行(# Time# User@Host# Query_time、实际 SQL),简单按行切分会导致 SQL 被

    截断或错位
  • 同一逻辑 SQL 参数不同(如 SELECT * FROM orders WHERE user_id = 1001 vs ...user_id = 1002)会被当作两条,无法聚合成“同一类”
  • 未过滤注释、空行、非查询语句(如 SETUSE),干扰统计结果

更稳妥的做法是用 pt-query-digest(Percona Toolkit):

  • 自动解析日志结构,提取完整 SQL
  • 支持按 fingerprint(抽象语法树哈希)归类,比简单正则可靠得多
  • 可输出调用频次、平均延迟、锁等待时间等多维指标

高频 SQL 不一定等于问题 SQL,怎么判断是否真要优化?

执行次数高 ≠ 必须优化。比如一个 SELECT COUNT(*) FROM status WHERE type = 'active' 每秒跑 50 次,如果走索引且响应稳定在 0.5ms,它只是“忙”,不是“病”。

判断依据建议组合看三项:

  • calls(调用次数)是否显著高于其他语句(例如 Top 3 占总查询量 70%+)
  • avg_timemean_time 是否持续高于 P95 基线(比如多数查询
  • 对应表是否频繁出现在 SHOW ENGINE INNODB STATUSSEMAPHORESTRANSACTIONS 区域(暗示锁争用)

特别注意:缓存层(如 Redis)未覆盖的“高频 + 低变更”查询,往往比“低频 + 高耗时”的更值得加缓存——因为优化收益是乘数关系,不是加法。