一句话总结
慢查询排查遵循开启日志 → 定位SQL → EXPLAIN分析 → 优化的流程。重点关注type(至少ref级别)、key(是否命中索引)、rows(扫描行数)、Extra(Using filesort/temporary需优化)。
初级理解
开启慢查询日志:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1 # 超过1秒记录
log_queries_not_using_indexes = 1 # 记录未使用索引的查询
查看当前查询:
SHOW FULL PROCESSLIST;
-- 重点关注 Time 列(执行时长)和 State 列(如 Sending data)
一句话总结:开启慢查询日志 → 用SHOW PROCESSLIST定位 → EXPLAIN分析执行计划。
中级深入
EXPLAIN重点关注字段:
EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'PAID';
• type(访问类型):性能从优到劣:system > const > eq_ref > ref > range > index > ALL。出现ALL代表全表扫描,必须优化。
• key:实际使用的索引。若为NULL说明未命中索引。
• rows:预估扫描行数。数值越大性能越差。
• Extra(重要!):
- Using filesort:使用了额外的排序操作,需优化索引
- Using temporary:使用了临时表,常见于GROUP BY,性能极差
- Using index:覆盖索引,无需回表,性能极佳
注意:type达到ref级别才算合格,range级别在范围查询时可以接受,ALL必须优化。
高级拓展
优化手段:
1. 加索引:针对WHERE、JOIN、ORDER BY字段建立合适的联合索引
2. 改写SQL:避免在索引列上做函数运算,将OR改写为UNION ALL
3. 避免SELECT *:只查询需要的字段,提高覆盖索引命中率
4. 深分页优化:LIMIT 100000, 10 改为 游标分页 WHERE id > lastId LIMIT 10
慢查询优化案例:
-- 问题SQL:type=ALL, rows=1000000
EXPLAIN SELECT * FROM orders WHERE YEAR(create_time) = 2024;
-- 优化:索引列不参与函数运算
EXPLAIN SELECT * FROM orders
WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01';
-- type=range, rows=50000
面试加分项:能说出EXPLAIN各字段含义、type级别含义、常见优化手段,说明你有慢查询排查实战经验。
实战场景
场景:线上订单查询变慢排查
-- 1. 查看慢查询日志
tail -f /var/log/mysql/slow.log
-- 2. 发现慢SQL
SELECT * FROM orders WHERE user_id = 100 ORDER BY create_time DESC LIMIT 20;
-- 执行时间: 3.5秒
-- 3. EXPLAIN分析
EXPLAIN SELECT * FROM orders WHERE user_id = 100 ORDER BY create_time DESC LIMIT 20;
-- type: ref, key: idx_user_id, rows: 50000, Extra: Using filesort
-- 4. 优化:建立联合索引
CREATE INDEX idx_user_time ON orders(user_id, create_time);
-- 执行时间: 0.01秒
面试模拟
Q:EXPLAIN中type为ALL说明什么?
A:type=ALL代表全表扫描,MySQL需要扫描整张表来查找匹配的行,性能极差。出现ALL时必须优化,通常是缺少索引或索引失效导致的。
Q:Using filesort和Using temporary分别是什么?
A:Using filesort表示MySQL需要额外的排序操作,无法利用索引的有序性;Using temporary表示使用了临时表,常见于GROUP BY或多表JOIN。两者都会导致性能下降,需要通过建立合适的索引来优化。