MySQL优化查询速度,explain分析执行计划
前言
SQL查得慢,不知道为什么慢。用EXPLAIN看MySQL怎么执行这条SQL,就能找到问题在哪。
一、EXPLAIN怎么用
EXPLAIN SELECT * FROM users WHERE name = '张三';
输出很多列,重点看这几个:id、select_type、table、type、key、rows、Extra。
二、重点列详解
1. type(访问类型)
最重要的一列,看SQL查得快不快。
从好到差:
| type | 说明 | 速度 |
|---|---|---|
| system | 表只有一行 | 最快 |
| const | 主键或唯一索引查一次 | 很快 |
| eq_ref | 联表时主键关联 | 很快 |
| ref | 非唯一索引查 | 快 |
| range | 索引范围扫描 | 中 |
| index | 扫整个索引树 | 慢 |
| ALL | 全表扫描 | 最慢 |
目标: 至少达到range,最好是ref以上。
如果type是ALL,就是全表扫描,必须优化。
2. key(实际用到的索引)
key: NULL
说明没用索引。
key: idx_name
说明用到了idx_name索引。
3. rows(扫描行数)
MySQL预估要扫描多少行。
rows越大,越慢。
4. Extra(额外信息)
常见的:
- Using where:WHERE过滤
- Using index:覆盖索引,不用回表,好
- Using filesort:需要额外排序,不好
- Using temporary:用了临时表,不好
三、常见问题
问题1:type=ALL,全表扫描
原因: 没加索引,或者索引失效。
解决: 给WHERE条件的字段加索引。
问题2:key=NULL,没用索引
原因:
- 没建索引
- 索引失效了(函数、类型转换、前导模糊查询等)
解决: 建正确的索引,避免索引失效写法。
问题3:Using filesort
原因: ORDER BY的字段没走索引。
解决: 给ORDER BY的字段加索引。
问题4:Using temporary
原因: GROUP BY或DISTINCT用了临时表。
解决: 给GROUP BY的字段加索引。
四、实战案例
慢SQL
SELECT * FROM orders WHERE user_id = 100 ORDER BY create_time DESC LIMIT 10;
EXPLAIN结果:
| id | select_type | table | type | key | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | SIMPLE | orders | ALL | NULL | 100000 | Using where; Using filesort |
问题:
- type=ALL,全表扫描
- key=NULL,没用索引
- rows=100000,扫了10万行
- Using filesort,还要额外排序
优化
加联合索引:
ALTER TABLE orders ADD INDEX idx_userid_createtime (user_id, create_time);
再EXPLAIN:
| id | select_type | table | type | key | rows | Extra |
|---|---|---|---|---|---|---|
| 1 | SIMPLE | orders | ref | idx_userid_createtime | 10 | Using where |
优化效果:
- type变成ref
- 用到了索引
- rows从10万变成10
- 没有filesort了
五、常用优化技巧
1. 避免SELECT *
只查需要的列,能用上覆盖索引。
2. WHERE条件加索引
经常查询的字段加索引。
3. 联合索引最左前缀
联合索引 (a,b,c),查询条件要从最左列开始。
4. 避免索引失效
- 不要对索引字段用函数
- 不要隐式类型转换
- 不要前导模糊查询
like '%xxx'
总结
EXPLAIN看这三点:
- type:是不是全表扫描
- key:有没有用到索引
- rows:扫描了多少行
记住: 慢SQL先EXPLAIN,找到问题再优化。
遇到问题加QQ23979811 协助处理
MySQL 索引优化实战:从 Explain 分析到查询性能翻倍
前言
数据库查询慢是 Web 开发中最常见的性能问题之一。而绝大多数慢查询都可以通过合理使用索引来解决。本文将从 Explain 执行计划入手,带你一步步掌握 MySQL 索引优化的实战技巧。
一、认识 Explain 执行计划
要优化查询,首先得知道 MySQL 是怎么执行你的 SQL 的。EXPLAIN 命令可以展示 MySQL 执行查询的详细步骤:
EXPLAIN SELECT * FROM orders WHERE user_id = 10086 AND status = 'paid';
重点关注以下几个字段:
- type:访问类型,从好到差依次为
const > eq_ref > ref > range > index > ALL。出现ALL就是全表扫描,必须优化。 - key:实际使用的索引。如果为 NULL,说明没有用到索引。
- rows:预估需要扫描的行数。这个值越大越慢。
- Extra:额外信息。
Using filesort和Using temporary都是危险信号。
二、最左前缀原则
联合索引 (a, b, c) 的匹配规则:
-- 用到索引 a,b,c
SELECT * FROM t WHERE a = 1 AND b = 2 AND c = 3;
-- 用到索引 a,b
SELECT * FROM t WHERE a = 1 AND b = 2;
-- 只用到索引 a(中间断了)
SELECT * FROM t WHERE a = 1 AND c = 3;
-- 完全用不到索引
SELECT * FROM t WHERE b = 2 AND c = 3;
实战要点:把等值查询的列放在前面,范围查询的列放在后面。
三、常见索引失效场景
1. 对索引列使用函数或运算
-- 失效:对索引列用了函数
SELECT * FROM users WHERE DATE(created_at) = '2026-01-01';
-- 有效:改成范围查询
SELECT * FROM users WHERE created_at >= '2026-01-01' AND created_at < '2026-01-02';
2. 隐式类型转换
-- 失效:phone 是 varchar,用数字查
SELECT * FROM users WHERE phone = 13800138000;
-- 有效:加引号
SELECT * FROM users WHERE phone = '13800138000';
3. LIKE 以通配符开头
-- 失效
SELECT * FROM users WHERE name LIKE '%张%';
-- 有效
SELECT * FROM users WHERE name LIKE '张%';
四、实战优化案例
问题 SQL(扫描 10 万行,耗时 1.2 秒):
SELECT id, title, created_at FROM articles
WHERE category_id = 5 AND status = 'published'
ORDER BY created_at DESC LIMIT 20;
Explain 结果:type=index,rows=120000,Using filesort。
优化方案:创建联合索引
ALTER TABLE articles ADD INDEX idx_cat_status_time (category_id, status, created_at DESC);
优化后:type=ref,rows=20,Extra 无 filesort。查询时间从 1.2 秒降到 0.005 秒。
五、索引不是越多越好
索引虽然能加速查询,但也有代价:
- 写入变慢:每次 INSERT/UPDATE 都要维护索引
- 占用空间:索引也是要存磁盘的
- 优化器选错:索引太多可能让优化器犯迷糊
建议:单表索引数量控制在 5 个以内,避免重复索引和冗余索引。
总结
MySQL 索引优化的核心思路:
- 用
EXPLAIN看执行计划,找到慢的原因 - 遵循最左前缀原则设计联合索引
- 避免常见的索引失效写法
- 定期清理无用索引
掌握这些技巧,你就能解决 80% 以上的慢查询问题。