«

MySQL慢查询排查,explain分析SQL执行计划

时间:2026-10-9 07:49     作者:emer     分类: 无


前言

网站突然变慢,数据库CPU100%?多半是慢查询搞的鬼。本文讲怎么开启慢查询日志、用explain分析SQL执行计划,找到慢的原因。

一、开启慢查询日志

临时开启

-- 查看慢查询是否开启
SHOW VARIABLES LIKE 'slow_query_log';

-- 开启慢查询
SET GLOBAL slow_query_log = ON;

-- 超过1秒就算慢查询
SET GLOBAL long_query_time = 1;

永久开启

编辑my.cnf:

vi /etc/my.cnf

加:

slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1

重启MySQL:

systemctl restart mysqld

看慢查询日志

tail -f /var/log/mysql/slow.log

二、explain是什么

explain用来分析SQL是怎么执行的,看有没有用索引、扫了多少行。

用法

EXPLAIN SELECT * FROM users WHERE name = '张三';

三、explain字段解释

id

SELECT的标识符,越大越先执行。

select_type

查询类型:

table

查的哪张表。

type(最重要)

访问类型,从好到差:

类型 含义
system 表只有一行
const 主键或唯一索引匹配,只查一行
eq_ref 主键或唯一索引匹配
ref 普通索引匹配
range 索引范围查询(between、>、<)
index 扫整个索引树
ALL 全表扫描(最坏!)

重点看: 出现ALL就是全表扫描,要加索引。

possible_keys

可能用到的索引。

key

实际用到的索引。

key是NULL就是没用到索引。

rows

预估要扫描多少行。

越大越慢。

Extra

额外信息:

值 含义
Using where 服务器在存储引擎返回后再过滤
Using index 用了覆盖索引,不错
Using temporary 用了临时表,不好
Using filesort 用了文件排序,不好

四、常见慢查询原因

原因1:没加索引

SELECT * FROM users WHERE name = '张三';

name字段没索引 → 全表扫描 → 慢。

解决: 加索引

ALTER TABLE users ADD INDEX idx_name(name);

原因2:索引失效

虽然加了索引,但SQL写法不对,索引用不上。

索引失效的情况:

  1. 对索引字段用函数:

    SELECT * FROM users WHERE LEFT(name, 3) = '张三'; -- 索引失效
  2. 索引字段用运算:

    SELECT * FROM users WHERE age + 1 = 20; -- 索引失效
  3. 最左前缀原则不满足:

    -- 联合索引(a, b, c)
    SELECT * FROM t WHERE b = 1; -- 索引失效
  4. like以%开头:

    SELECT * FROM users WHERE name LIKE '%张三%'; -- 索引失效
  5. 类型不匹配:

    -- phone是varchar
    SELECT * FROM users WHERE phone = 13800138000; -- 索引失效

原因3:SELECT *

查了不需要的字段,占内存。

解决: 只查需要的字段

SELECT id, name FROM users WHERE ...

原因4:大表分页越查越慢

SELECT * FROM users ORDER BY id LIMIT 100000, 10;

慢的原因: 要先扫10万行再跳过。

解决:

SELECT u.* FROM users u
INNER JOIN (SELECT id FROM users ORDER BY id LIMIT 100000, 10) t
ON u.id = t.id;

五、实战案例

慢SQL

SELECT * FROM orders WHERE user_id = 123 AND status = 1 ORDER BY create_time DESC LIMIT 10;

explain分析

EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 1 ORDER BY create_time DESC LIMIT 10;

发现: type是ALL,key是NULL → 全表扫描。

加索引

ALTER TABLE orders ADD INDEX idx_user_status_time(user_id, status, create_time);

再explain: type变成ref,key是idx_user_status_time → 用上索引了。

六、优化原则

  1. WHERE条件加索引
  2. ORDER BY字段加索引
  3. 联合索引遵守最左前缀
  4. **不要SELECT ***
  5. 避免在索引字段上用函数
  6. 大分页用子查询优化

七、常见坑

坑1:加了索引但没用

原因: SQL写法导致索引失效。

排查: explain看key字段。

坑2:索引加太多

索引不是越多越好,写的时候要维护索引,会变慢。

建议: 单表索引不超过5个。

坑3:区分度低的字段不加索引

比如gender(男/女),加索引没用。

原则: 区分度高的字段加索引。

总结

记住:

  1. 开启慢查询日志找慢SQL
  2. 用explain分析SQL执行计划
  3. type=ALL就是全表扫描,要加索引
  4. key=NULL就是没用到索引
  5. rows越大越慢
  6. 索引失效要避免

最常用:

EXPLAIN SELECT * FROM users WHERE ...

遇到问题加QQ23979811 协助处理

标签: MySQL Explain 索引 慢查询 sql优化