- 约1126字
- 技术
- 2026年4月27日
上周线上一个查询突然超时,查了半天才定位到问题。
同事说某个接口超时了,响应时间从200毫秒变成了30秒。我第一反应是数据量变大导致的,但查了数据库记录,最近一周数据只涨了5%,不应该啊。
后来用EXPLAIN分析了一下,发现问题根本不是数据量,而是一个看似简单的SQL压根没用索引。
什么是EXPLAIN
EXPLAIN是MySQL提供的查询分析工具,直接在SELECT前面加个EXPLAIN就能看到执行计划。不需要任何额外权限,用法非常简单:
EXPLAIN SELECT * FROM orders WHERE user_id = 12345;
执行后会返回一串字段,其中最关键的是这几个:
type:访问类型,ALL全表扫描最慢key:实际使用的索引rows:预计扫描行数Extra:额外信息,是否 Using filesort、Using temporary
5种常见问题的EXPLAIN特征
1. 全表扫描(type = ALL)
+----+-------------+-------+------+---------------+
| id | select_type| type | key | rows |
+----+-------------+-------+------+---------------+
| 1 | SIMPLE | ALL | NULL| 5000000 |
+----+-------------+-------+------+---------------+
这种就是最糟糕的情况,500万行全扫描。赶紧检查WHERE条件字段有没有索引。
2. 索引失效(type = ref 但 key = NULL)
明明有索引为什么不走?常见原因:
- 类型不匹配:字符串字段用数字WHERE
- 函数处理:WHERE YEAR(created_at) = 2026
- 隐式转换:字符串字段没加引号
3. 索引选择性低(rows 接近全表)
| 1 | SIMPLE | index | idx_xxx| 4800000 |
虽然用了索引,但扫描行数接近全表。这种情况考虑加 selectivity 更高的条件,或者改用复合索引调整字段顺序。
4. Using filesort(Extra 包含这个)
| Extra |
| Using filesort; Using where |
意味着MySQL需要在内存中额外排序,数据量大时会明显变慢。解决办法是让ORDER BY字段也走上索引。
5. Using temporary(Extra 包含这个)
| Extra |
| Using temporary; Using filesort|
创建了临时表,通常是GROUP BY或DISTINCT没走上索引。先确保分组字段有索引。
快速定位问题4步法
第一步:运行EXPLAIN,看type字段是不是ALL 第二步:检查key字段是不是NULL 第三步:看rows是不是远大于实际返回行数 第四步:检查Extra有没有filesort或temporary
按照这个顺序,5分钟内基本能定位90%的慢查询原因。
实际案例
回到开头那个30秒的查询,EXPLAIN结果是这样的:
EXPLAIN SELECT * FROM orders WHERE created_at > '2026-01-01';
+----+-------------+-------+------+---------------+
| id | select_type| type | key | rows |
+----+-------------+-------+------+---------------+
| 1 | SIMPLE | ALL | NULL| 4800000 |
+----+-------------+-------+------+---------------+
问题很明显:created_at字段有索引,但查询用的是>范围查询,MySQL预估这个条件会筛掉大量数据,所以直接走全表扫描。
改成带明确上界的范围查询后,响应时间回到了200毫秒。
小结
SQL慢不一定是因为数据量大,很可能是查询写法或索引使用有问题。学会用EXPLAIN,5分钟就能定位大多数性能瓶颈。
下次遇到查询超时,别急着加服务器配置,先跑一下EXPLANGE看看执行计划。多数时候,问题在代码层面就能解决。