慢查询的判定标准不是“感觉慢”,而是有明确阈值
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 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 更有效。慢查询日志里反复出现的语句,才值得投入精力深挖。
