MySQL 性能优化必修课:索引、慢 SQL、执行计划一次讲透
数据库性能,是后端系统 80% 性能瓶颈的源头。
你优化 JVM、优化 GC、优化线程池都可以,但只要 SQL 写得一般般 —— 系统一样会慢。
所有高并发架构师,都必须掌握 MySQL 性能优化的底层方法论:
如何设计高性能索引
如何定位慢 SQL
如何阅读与优化执行计划
如何避免回表、避免 Using Filesort
如何让 MySQL “走你预期的索引”
如何写出高性能分页、统计、聚合语句
本篇我们直接从实战出发,讲开发者真正会遇到的问题。
一、MySQL 性能优化的三大方向
所有 MySQL 性能优化,都绕不开三件事:
减少扫描行数(最核心)
减少 I/O 次数(SSD/GCP 下仍然关键)
减少锁争用(高并发场景尤为重要)
而索引,就是减少扫描行数的最重要方式。
二、索引优化:高性能 SQL 的第一原则
1)为什么非要建索引?
因为 MySQL 的查询过程,本质上就是:
通过索引定位尽可能少的行 → 回表获取数据 → 返回结果
如果你没有索引,那 MySQL 只能全表扫描(Full Table Scan)。
想象一张 1000 万行的表,全表扫描就是血崩。
2)最常见的索引误区(你一定见过)
❌ 误区 1:给所有字段都加索引
过度索引会导致:
写入变慢(所有索引都要同步维护)
占用更多磁盘
大多数索引根本不会被用到
❌ 误区 2:联合索引顺序随便写
(a, b, c) 与 (c, b, a) 完全不是一回事!
MySQL 使用联合索引必须遵循最左前缀原则。
❌ 误区 3:模糊查询用 %keyword% 期待走索引
%keyword% 永远不会走 B+ 树索引。
要优化全文检索请使用:
ES
MySQL FULLTEXT
3)高性能索引的黄金原则
原则 1:高区分度字段优先
区分度 = 去重后的数量 / 总行数
越接近 1 越好。
适合做索引的:
手机号
用户 ID
订单号
不适合做索引的:
性别(就 3 个值)
状态(0/1)
原则 2:范围查询要放在索引最后
例如:
WHERE user_id = ? AND create_time BETWEEN ? AND ?索引应建:
(user_id, create_time)但不能反过来!
原则 3:联合索引覆盖越多字段越好
例如:
SELECT id, name, age FROM user WHERE name = ? AND age = ?如果你建了:
(name, age, id)就能做到 覆盖索引(Covering Index),不需要回表,大幅提升性能。
三、慢 SQL 定位套路:遇到性能问题的第一步
线上 90% 的性能问题都可以通过慢 SQL 日志定位。
1)开启慢查询日志
在 my.cnf:
slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 1执行超过 1 秒的 SQL 会被记录
没走索引的 SQL 也会被记录
2)如何分析慢查询日志?
用工具:
pt-query-digest(强烈推荐)
阿里云 RDS 慢 SQL 控制台
腾讯云 SQL 分析
这些工具会告诉你:
哪些 SQL 最慢
哪些 SQL 调用次数最多
哪些 SQL 扫描行数最多
哪些 SQL 占总耗时 80%
让你精准定位热点。
四、执行计划(EXPLAIN)阅读与优化
你必须学会看 EXPLAIN,因为它能告诉你:
是否走索引
走的是哪个索引
扫描了多少行
是否出现 Using Filesort / Using Temporary(很糟糕)
是否产生回表
下面来拆解关键字段。
1)key 字段:实际使用的索引
如果这里是 NULL,说明 没有用索引。
常见原因:
索引不符合最左前缀原则
模糊搜索
%xxx类型不一致(字符串 vs 数字)
2)rows 字段:扫描行数(越小越好)
例如:
rows = 1非常好。
rows = 1,000,000SQL 基本废了。
3)extra 字段:重点关注两个
❌ Using Filesort
表示排序没有走索引排序,性能极差。
❌ Using Temporary
表示产生临时表,一般出现在 GROUP BY 或复杂排序中。
出现这两个标签时,必须优化。
五、实战案例:SQL 为啥不走索引?怎么改?
案例 1:字段类型不一致
SQL:
SELECT * FROM user WHERE id = '123';数据库:
id INT类型不一致,会导致全表扫描。
解决:传参用整数。
案例 2:函数导致索引失效
WHERE DATE(create_time) = '2025-12-01'因为 DATE(create_time) 对字段做了运算,索引失效。
优化:
WHERE create_time >= '2025-12-01 00:00:00'
AND create_time < '2025-12-02 00:00:00'案例 3:OR 导致索引失效
WHERE user_id = ? OR phone = ?OR 会让 MySQL 放弃索引。
优化方法:
改成 union
或者使用索引合并(MySQL 8.0 有时会自动触发)
六、高性能 SQL 写法模板(直接可用)
✅ 高性能分页
SELECT id, name
FROM user
WHERE id > ?
ORDER BY id
LIMIT 100;
比 OFFSET 快几十倍。
✅ 高性能计数
不要写:
SELECT COUNT(*) FROM big_table;在 5000 万行大表会非常慢。
优化:
维护冗余 count
使用近似算法(HyperLogLog)
分库分表时,分片并行 count
✅ 条件动态 SQL 优化
不要在 WHERE 条件写:
WHERE (name = ? OR ? IS NULL)这会让索引失效。
正确做法是动态拼接 SQL。
七、总结
MySQL 优化的核心思想只有一句话:
让 MySQL 尽量扫描更少的行。
做到这一点,你的 SQL 性能自然提升一个维度。
本篇我们讲了:
索引设计的黄金法则
慢 SQL 定位方法
EXPLAIN 的关键字段
常见执行计划陷阱
真实 SQL 优化案例
高性能 SQL 模板
下一篇我们继续讲:
默认评论
Halo系统提供的评论