MySQL索引优化实战:从慢查询到执行计划,新手也能照着做

当MySQL查询变慢时,优化的核心思路是先用慢查询日志找到具体是哪条SQL慢,再用EXPLAIN看它有没有走索引,最后针对性地加索引或改SQL。
下面按这个顺序展开,命令和配置都可以直接复制到测试环境执行。

先确认环境并开启慢查询日志

这套流程适用于MySQL 5.7和8.0,操作前建议在测试库或从库先验证,避免直接在生产主库上改配置。

登录MySQL后,先查看当前状态:

SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';

如果slow_query_log是OFF,可以临时开启(重启后失效):

SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = ON;

要永久生效,修改配置文件/etc/my.cnf(或/etc/mysql/my.cnf),在[mysqld]段落下添加:

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

改完重启MySQL:systemctl restart mysqld。注意:log_queries_not_using_indexes在并发高时会产生大量日志,
生产环境建议只在排查阶段临时打开。

从慢查询日志里找出要优化的SQL

日志文件默认在/var/log/mysql/slow.log,可以用mysqldumpslow快速汇总:

mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

-s t表示按总耗时排序,-t 10表示只显示前10条。
找到耗时最高、出现次数最多的那条SQL,记下它的完整语句。

如果日志里SQL被截断,可以在MySQL里执行:

SHOW VARIABLES LIKE 'slow_query_log_file';

确认路径后,用tail -f实时观察新产生的慢查询。

用EXPLAIN判断索引是否生效

拿到慢SQL后,在前面加EXPLAIN执行:

EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 1;

重点看这几列:

  • type:ALL是全表扫描,最差;ref、range、eq_ref、const依次更好。
  • key:实际使用的索引名。如果是NULL,说明没走索引。
  • rows:预估扫描行数,越小越好。
  • Extra:出现Using filesort或Using temporary通常意味着需要额外排序或临时表,是优化重点。

假设orders表有100万行,user_id和status各有单列索引,但type还是ALL,说明优化器没选索引,或者条件写法导致索引失效。

常见索引失效场景与修正写法

以下情况会让索引用不上,逐条对照检查:

  • 在索引列上做运算或函数:WHERE YEAR(created_at) = 2024改成WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'。
  • 隐式类型转换:user_id是varchar,却写WHERE user_id = 100,应写成WHERE user_id = '100'。
  • 前导模糊匹配:LIKE '%abc'无法走索引,LIKE 'abc%'可以。
  • OR连接的条件中有一个列没索引,整个查询可能退化为全表扫描。

对于多条件查询,可以考虑联合索引。
例如:

ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);

联合索引要遵守最左前缀原则:WHERE user_id = 100能用,WHERE status = 1单独用不上。加索引前先确认字段区分度,
区分度太低的列(如性别)单独建索引意义不大。

优化后的验证与回滚准备

执行ALTER TABLE加索引后,再次运行EXPLAIN,确认type变成ref或range,key显示新建的索引名,rows明显下降。

然后用实际查询测速:

SELECT SQL_NO_CACHE COUNT(*) FROM orders WHERE user_id = 100 AND status = 1;

对比优化前后的耗时。
如果效果不理想,可以删除索引回滚:

ALTER TABLE orders DROP INDEX idx_user_status;

避坑提醒:大表加索引会锁表或占用大量IO,MySQL 5.7以上支持ALGORITHM=INPLACE,但仍建议在业务低峰期操作,并提前确认磁盘空间。
不要一次加太多索引,每个索引都会增加写入开销。

几个新手常问的点

索引是不是越多越好? 不是。
索引会占用磁盘,并让INSERT、UPDATE、DELETE变慢。
只给高频查询条件、排序和连接字段建索引。

为什么加了索引还是慢? 可能是数据量太大、回表次数多,或者查询返回了大部分数据,这时优化器会认为全表扫描更快。
可以尝试覆盖索引,把SELECT的列也放进索引里。

EXPLAIN的rows准吗? 它是估算值,基于统计信息。
如果偏差很大,可以执行ANALYZE TABLE 表名;更新统计信息后再看。

生产环境能直接改吗? 建议先在从库或测试库验证,确认SQL和索引效果后再上生产,并保留回滚用的DROP INDEX语句。

分享到:
上一篇
MySQL主从复制配置全流程:从零搭建到状态验证
下一篇
mysqldump备份实战:从单库导出到定时自动备份
1
系统公告

泽御云中秋国庆双节活动上线:新购8折,拼团3.99元起

尊敬的用户:
泽御云“月满中秋·礼贺国庆”双节活动现已开启,活动时间为2026年9月23日至10月10日。 活动期间可享以下福利:
1. 常规云服务器新购使用优惠码“泽御中秋国庆同乐”,符合条件的订单享8折优惠。
2. 香港精品云服务器5人拼团低至3.99元,部分4核4G套餐3人拼团年付388元,续费同价。
3. 新用户购买年付云服务器,符合活动规则可赠送2个月使用时长。
4. 老用户续费季度赠15天,续费年度赠2个月;活动期间升级配置免收配置迁移手续费。
5. 推荐好友成功下单,符合条件的推荐人可获赠7天服务器使用时长。
6. 活动期间享宕机补偿标准翻倍、简单网站迁移协助及技术工单优先处理权益。
温馨提示:优惠码不适用于拼团套餐、活动轻量产品、年付订单及续费订单;拼团套餐为独立特价活动,不与赠时类福利叠加。赠送时长不可折现、退款或跨账户转移,具体规则以活动页面说明为准。
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意