慢查询往往源于缺失索引或一次扫描了过多数据行,排查时先看执行计划,再看表结构,最后对症下药。 页面加载缓慢、数据库CPU告警、SQL执行时间超过阈值,这些场景背后往往是同一个逻辑:查询没有走最优路径,缺失索引让你从第一行翻到最后一行,扫描行数过多则让你在定位之后还要读取大量数据,理解这两点,慢查询问题就解决了一半。
慢查询怎么排查?先定位那些"磨蹭"的SQL
慢查询就像团队里干活最慢的那个成员,先得把ta从一堆SQL里揪出来,MySQL提供了慢查询日志,开启后就能记录执行时间超过阈值的语句,操作路径很简单,在客户端执行三条命令:
- 开启慢查询日志:
SET GLOBAL slow_query_log = 'ON'; - 设置阈值:
SET GLOBAL long_query_time = 1;(超过1秒的SQL会被记录) - 确认日志文件位置:
SHOW VARIABLES LIKE 'slow_query_log_file';
日志拿到手,别急着改代码,对每条慢SQL执行EXPLAIN,重点看两个字段:type和rows。type显示ALL,意味着全表扫描,大概率没走索引;rows是预估扫描行数,数字越大越危险,业内专家指出,慢查询日志是性能排查的第一入口,但真正的病根要靠执行计划来确定。
举一个常见场景:订单后台按客户邮箱查历史订单,表里已有几百万行,email字段没有索引,这条SQL执行EXPLAIN时type是ALL,rows逼近全表行数,这时给email加上索引,type会变成ref,查询时间从秒级降到毫秒级。
mysql慢查询优化:索引缺失与扫描行数多
优化慢查询,本质上是在解决两个问题:数据库有没有走索引,以及一次到底扫了多少行,下面拆开来说。
缺失索引:全表扫描的"笨办法"

没有索引的查询,数据库只能逐行读取,直到把整张表翻完,就像在一个没有目录的书里找一句话,只能从第一页翻到最后一页,如果表数据量不大,全表扫描没什么感觉;一旦数据量上来,慢就是必然的。
判断方法很直接:
- 执行
EXPLAIN,看type字段是否等于ALL。 - 看
rows字段是否接近全表行数。 - 查看表结构,确认查询条件里的列是否有索引。
解决方式也简单,给高频查询的列加索引:
ALTER TABLE orders ADD INDEX idx_email (customer_email);
加索引后要复查一次执行计划,确认新索引真的被用上了,有时候查询条件里用了函数或隐式转换,索引也会失效,比如WHERE DATE(create_time) = '2026-01-01',这种写法会让索引形同虚设,改为范围查询WHERE create_time >= '2026-01-01' AND create_time < '2026-01-02'更合理。
扫描行数过多:有索引也未必快
另一种情况是索引没少建,但查询依然慢,问题出在扫描行数上,比如WHERE status = 'pending',这个字段有索引,可表中大部分行都是pending状态,索引帮你定位到第一条后,后续的读取量依然巨大,还有SELECT 带来的回表开销,每行都要回到主表获取完整数据,耗时自然高。
常见优化技巧:
- 只查需要的列,避免
SELECT。 - 用覆盖索引,让查询在索引页内就能拿到所有字段,省掉回表。
- 大范围查询分成多次小查询,或用
LIMIT控制单次返回量。 - 深分页慢的场景,可以先定位起始ID,再用
WHERE id > ? ORDER BY id LIMIT 20替代LIMIT 100000, 20。
| 问题类型 | 典型迹象 | 优化方案 |
|---|---|---|
| 缺失索引 | type=ALL,rows接近全表行数 |
添加合适索引 |
| 索引失效 | 索引列上有函数运算或隐式转换 | 改写SQL,去除函数操作 |
| 扫描行数过多 | 走了索引但rows仍然很大 |
覆盖索引、分页、拆分查询 |
慢查询优化和索引调整的对比:哪种更适合你
很多人一遇到慢查询就急着加索引,但索引不是万能药,在不同场景下,优化手段的优先级不同,这里做几组对比:
- 加索引:见效最快,适合查询多、写入少的表,但索引占用空间,每次插入、更新都要维护索引结构,索引过多反而拖累写入性能。
- 改写SQL:把大查询拆成小查询,去掉多余的关联和子查询,效果持久且对资源友好,缺点是涉及业务代码改动,测试成本高。
- 调整数据库配置:比如增大排序缓冲区、调整连接数,能缓解一时压力,但治标不治本,适合应急。
行业共识认为,一次好的优化往往是组合拳:先用索引解决大部分问题,再用SQL改写收尾,如果业务允许,还可以考虑在应用层做缓存,进一步减少数据库压力。
慢查询分析工具与免费方案有哪些
慢查询日志是文本格式,量大了肉眼根本看不过来,常用工具有以下几种:
mysqldumpslow:MySQL自带的汇总工具,按执行次数、耗时排序,免费,用法示例:mysqldumpslow -s t -t 10 slow.log,取平均耗时最长的10条SQL。pt-query-digest:Percona Toolkit中的核心工具,能生成可读的HTML报告,支持多维度分析,免费开源。Performance Schema:数据库内部性能监控表,可以实时查询慢语句,无需额外安装。

如果你的数据库部署在云上,云厂商控制台通常自带慢查询分析功能,直接在控制台看排行榜即可,各大数据服务商的产品页面都接入了这一能力,不需要自己搭环境。
慢查询日志分析工具哪个好?如果你只是偶尔排查问题,mysqldumpslow足够用;如果天天跟慢SQL打交道,建议用pt-query-digest,商业监控工具功能全面,但通常按实例收费,小项目或者预算有限的团队,用免费方案完全能解决多数问题。
回到最初的话题:慢查询的来源并不复杂,缺索引和扫描行数过多加在一起,覆盖了绝大多数慢SQL,遇到慢查询,先开日志,再执行EXPLAIN看执行计划,最后针对性地加索引或改写SQL,别一上来就调参数,那是舍本求末。
关于慢查询索引优化的三个常见问题
为什么加了索引还是慢?
加了索引但执行计划没用上,常见原因有三个:索引列上做了函数运算,比如WHERE DATE(create_time) = '2026-01-01'会让索引失效;隐式类型转换也会失效,比如字符串列用数字去比较;还有可能是范围查询导致扫描行数依然很大,用EXPLAIN看type和rows字段,能直接找到答案。
慢查询日志文件太大怎么办?
可以用mysqldumpslow按累计耗时汇总,先处理Top 10的SQL,针对历史日志,定期备份后清空,或者用pt-query-digest自动轮转分析,日志本身是排查依据,及时归档就好。
索引是不是越多越好?
不是,每个索引都会占用磁盘空间,且每次插入、更新、删除时都要同步维护索引,表中索引过多,写入性能会明显下降,只给高频查询的列和常用过滤条件建索引,低选择性的列,比如性别,这类值很少的列通常不适合建索引。
