一、SQL 为什么会慢?
根本原因 3 个:
- 没走索引 / 索引失效(全表扫描)
- 数据量太大(没分页、没过滤)
- 写法复杂(子查询嵌套、join 太多、排序分组无索引)
二、索引(SQL 优化的核心)
1. 什么是索引?
可以理解为书的目录:
- 没有索引 = 一页一页翻(全表扫描)
- 有索引 = 直接查目录定位(快速查找)
2. 最常用索引类型
- 主键索引(PRIMARY KEY) 唯一、非空、最快
- 唯一索引(UNIQUE) 列值不能重复
- 普通索引(INDEX) 最常用,加速查询
- 联合索引(复合索引) 最关键! 多列一起建索引
3. 联合索引最左前缀原则
索引
(a, b, c)
- 能命中:
where a=?、where a=? and b=?、where a=? and b=? and c=? - 不能命中:
where b=?、where c=?、where b=? and c=?
一句话:必须从左到右连续使用,不能跳过前面的列。
4. 哪些情况索引会失效?(高频)
- 索引列上运算 / 函数:
where age+1=10、where substr(name,1,2)='ab' - 隐式类型转换:
where phone=13800138000(phone 是字符串) - like 以 % 开头:
where name like '%张三' - 使用!= /not in /is not null(会导致索引失效)
- or 连接非索引列
- 联合索引不满足最左前缀
5. 建索引的最佳实践
- where 经常查询的列建索引
- group by / order by 字段建索引
- join 关联字段建索引
- 不要滥用索引(写入会变慢)
- 区分度低的列不要建索引(如性别、状态)
- 优先用联合索引,少用多个单值索引
三、执行计划(看懂 SQL 到底怎么跑)
使用命令(MySQL):
EXPLAIN SELECT * FROM user WHERE name = '张三';
重点看 3 个字段
- type(最重要) 性能从好到坏:
system > const > eq_ref > ref > range > index > ALL- ALL = 全表扫描(必须优化)
- ref = 走了索引(良好)
- range = 范围索引(良好)
- key 实际使用了哪个索引,为 NULL 表示没走索引。
- Extra
Using filesort:文件排序(必须优化)Using temporary:用到临时表(必须优化)Using index:覆盖索引(最优)
四、常见慢查询 + 优化方案
1. 慢查询 1:全表扫描
SELECT * FROM user WHERE name = '张三';
优化:给 name 建索引
CREATE INDEX idx_name ON user(name);
2. 慢查询 2:like % xxx(索引失效)
SELECT * FROM user WHERE name LIKE '%张三';
优化:
- 业务允许:改成
LIKE '张三%' - 必须模糊:用 ES 或 MySQL 全文索引
3. 慢查询 3:索引列上用函数
SELECT * FROM user WHERE YEAR(create_time) = 2025;
优化:
SELECT * FROM user
WHERE create_time >= '2025-01-01'
AND create_time < '2026-01-01';
4. 慢查询 4:order by 无索引
SELECT * FROM user ORDER BY create_time DESC;
优化:给排序字段建索引
5. 慢查询 5:join 无索引
SELECT * FROM order o
JOIN user u ON o.user_id = u.id
WHERE u.name = '张三';
优化:
order.user_id建索引user.name建索引
6. 慢查询 6:not in / != 导致索引失效
SELECT * FROM user WHERE status != 1;
优化:
- 改用范围
- 或业务上调整为正向查询
7. 慢查询 7:分页太深
SELECT * FROM user LIMIT 1000000,10;
优化:
SELECT * FROM user
WHERE id > 1000000
LIMIT 10;
五、SQL 优化便签
- 先看是否走索引
- 避免全表扫描(type=ALL)
- 索引列不运算、不函数
- 联合索引遵守最左前缀
- 少用 select *,只查需要的列
- join 必须加索引
- 深度分页用主键过滤
- 避免 Using filesort 和 Using temporary
六、快速排查慢查询步骤
- 开启慢查询日志
- 用
EXPLAIN看执行计划 - 看
type是否 ALL(全表扫描) - 看
key是否为 NULL(没走索引) - 看
Extra是否有文件排序 / 临时表 - 建索引 / 改 SQL 重新验证
总结
- 索引是 SQL 优化的核心,联合索引最常用
- 执行计划判断 SQL 好坏
- 慢查询 90% 是索引问题
- 索引列不运算、不函数、不隐式转换
文章摘自:https://www.cnblogs.com/chuansheng/p/19914144
