mysql慢查询是如何判定的_mysql执行慢查询分析

2次阅读

慢查询判定标准是执行时间超过long_query_time阈值(默认10秒,生产常用0.1–0.2秒),需永久配置slow_query_log等参数,并结合真实数据环境用explain分析,优先优化高选择性字段索引与访问模式。

mysql慢查询是如何判定的_mysql执行慢查询分析

慢查询的判定标准不是“感觉慢”,而是有明确阈值

mysql 官方定义:执行时间超过 long_query_time 参数设定值的 SQL,就会被记为慢查询。默认是 10 秒,但生产环境几乎从不这么设——它只是个起点,不是合理值。

真实业务中,这个值往往压到 0.2(200ms)甚至 0.1(100ms)。比如一个高并发电商订单页,接口 SLA 要求 P99 ≤ 300ms,那数据库单条查询留出 100ms 都算宽裕;再往上拖,链路就容易超时。

  • long_query_time 是浮点数,但 MySQL 内部只保留一位小数(写 0.15 会被截成 0.1),所以别写太细
  • 该参数对“未命中查询缓存”的语句才生效;如果开启了 query cache 且命中,根本不会走执行阶段,自然也不计入慢日志
  • 注意:SET long_query_time = 0.2 只影响当前会话;必须加 GLOBAL 才对新连接生效:SET GLOBAL long_query_time = 0.2

怎么开慢查询日志?别只靠 SQL 临时开

线上环境必须永久开启,否则重启 MySQL 就失效,等于没开。临时命令只适合测试或救急:

  • 动态开启(立即生效,但重启丢失):SET GLOBAL slow_query_log = 1 + SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'
  • 永久生效:编辑 /etc/my.cnf[mysqld] 段,加这三行:
    slow_query_log = 1
    slow_query_log_file = /var/log/mysql/slow.log
    long_query_time = 0.2
  • 强烈建议加上:log_queries_not_using_indexes = 1 —— 即使没超时,但没走索引的查询也记下来,这类 SQL 往往是“潜伏慢查询”

验证是否生效:SHOW VARIABLES LIKE 'slow_query_log%'SHOW VARIABLES LIKE 'long_query_time'。别信“我开了”,要看变量值。

EXPLAIN 不是万能钥匙,用错顺序反而误导人

很多人一拿到慢 SQL 就直接 EXPLAIN,但这是最危险的一步:你解释的可能是开发环境里带 WHERE id = 1 的干净数据,而线上跑的是 WHERE user_id = 123456789,数据分布、索引选择性、执行计划全不一样。

  • 正确顺序是:先看慢日志 → 提取真实参数还原完整 SQL → 再在**同库同数据量级的从库或影子库**上 EXPLAIN
  • EXPLAIN 输出里重点盯三个字段:type(是否 ALL 全表扫描)、rows(预估扫描行数,和实际 select count(*) 对比)、Extra(有没有 Using filesortUsing temporary
  • 特别注意:key 显示用了哪个索引,但 key_len 才告诉你用了索引的前几列——如果建了联合索引 (a,b,c),但 key_len 只显示 a 的长度,说明 b/c 没用上

优化不是加索引就完事,得看访问模式和更新成本

加索引是最常见的操作,但也是最容易翻车的地方。比如给 status 字段加索引,看似解决了 WHERE status = 'pending',但如果该字段只有 3 个枚举值,索引区分度极低,MySQL 优化器大概率会弃用它,还是走全表扫描。

  • 优先考虑“高选择性字段”:比如 user_idorder_no,而不是 is_deletedgender
  • 联合索引要遵循最左前缀:想加速 WHERE a = ? AND b = ? ORDER BY c,索引应建为 (a, b, c),而不是 (a, c, b)
  • 写多读少的表慎加索引:每多一个索引,INSERT/UPDATE/DELETE 就得多维护一份 B+ 树,QPS 高时可能拖垮写入性能

真正难的从来不是“怎么加索引”,而是判断“这条 SQL 值不值得优化”——有时改业务逻辑(比如分页改游标)、拆查询、加缓存,比死磕 SQL 更有效。慢查询日志里反复出现的语句,才值得投入精力深挖。

text=ZqhQzanResources