数据库慢查询怎么排查?explain重点关注哪些字段?

2025年 阅读约 10 分钟 面试指南 · MySQL面试

MySQL慢查询排查全流程,从慢查询日志配置到EXPLAIN执行计划分析,附常见优化手段。

一句话总结

慢查询排查遵循开启日志 → 定位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。两者都会导致性能下降,需要通过建立合适的索引来优化。