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

慢查询的判定标准不是“感觉慢”,而是有明确阈值
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 = 1slow_query_log_file = /var/log/mysql/slow.loglong_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 filesort或Using temporary) - 特别注意:
key显示用了哪个索引,但key_len才告诉你用了索引的前几列——如果建了联合索引(a,b,c),但key_len只显示 a 的长度,说明 b/c 没用上
优化不是加索引就完事,得看访问模式和更新成本
加索引是最常见的操作,但也是最容易翻车的地方。比如给 status 字段加索引,看似解决了 WHERE status = 'pending',但如果该字段只有 3 个枚举值,索引区分度极低,MySQL 优化器大概率会弃用它,还是走全表扫描。
- 优先考虑“高选择性字段”:比如
user_id、order_no,而不是is_deleted、gender - 联合索引要遵循最左前缀:想加速
WHERE a = ? AND b = ? ORDER BY c,索引应建为(a, b, c),而不是(a, c, b) - 写多读少的表慎加索引:每多一个索引,
INSERT/UPDATE/DELETE就得多维护一份 B+ 树,QPS 高时可能拖垮写入性能
真正难的从来不是“怎么加索引”,而是判断“这条 SQL 值不值得优化”——有时改业务逻辑(比如分页改游标)、拆查询、加缓存,比死磕 SQL 更有效。慢查询日志里反复出现的语句,才值得投入精力深挖。










