MySQL性能调优的第一步是抓住慢查询,一条SQL扫描全表与走索引的耗时差距能达到百倍以上。本文从慢查询日志定位、EXPLAIN执行计划解读到索引重建策略,给出完整的MySQL慢查询优化流程,附带可直接套用的排查命令与案例。
开启慢查询日志定位问题SQL
MySQL默认关闭慢查询日志,按以下参数开启并配置阈值:
-- 动态开启
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = ON;
-- 查看当前设置
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
long_query_time=1表示超过1秒的SQL被记录,生产环境先按这个阈值跑一段时间,再根据日志量收敛。8.0里用performance_schema的events_statements_summary_by_digest表也能按SQL指纹聚合统计,配合sys.schema_unused_indexes可以找到从未使用的冗余索引。
EXPLAIN执行计划关键列解读
拿到慢SQL后用EXPLAIN看执行计划,重点读五列:
EXPLAIN SELECT o.order_no, u.name
FROM orders o
JOIN users u ON u.id = o.user_id
WHERE o.status = 1 AND o.created_at > NOW() - INTERVAL 7 DAY;
type列是访问类型,从好到差依次是system、const、eq_ref、ref、range、index、ALL,看到ALL就要优先建索引;key列显示实际使用的索引,为NULL说明没走索引;rows列是预估扫描行数,优化后应明显下降;Extra列出现Using filesort或Using temporary说明排序或分组没走索引,出现Using where配合type=ALL基本可以定位为全表扫描。
索引设计原则与常见失效场景
索引设计遵循最左前缀原则:复合索引(created_at, status, user_id)可以服务created_at范围、created_at+status精确、created_at+status+user_id三组查询,但跳过第一列直接查status不会命中。区分度低的列(status这类枚举)单独建索引收益很小,要放在复合索引靠后的位置。
索引失效的高频原因:函数包裹索引列WHERE DATE(created_at)='2026-09-01'会放弃索引,应改为created_at >= '2026-09-01' AND created_at < '2026-09-02';隐式类型转换如字符串字段与数字比较;LIKE '%keyword'前置通配符导致无法走索引;OR条件中有一个字段无索引会退化为全表扫描。
MySQL索引重建与统计信息更新
表数据大量变更后索引碎片率上升,扫描性能下降。通过SHOW TABLE STATUS LIKE 'orders'查看Data_free字段评估碎片,重建索引使用:
ALTER TABLE orders ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE;
ALTER TABLE重建表会整理数据页与索引页,Online DDL的ALGORITHM=INPLACE配合LOCK=NONE允许DML并发执行,大表建议在业务低峰执行并评估磁盘空间。统计信息过期导致优化器选错索引时,执行ANALYZE TABLE orders更新cardinality统计,必要时用FORCE INDEX或优化器提示校正。
分页查询与深分页优化
ORDER BY + LIMIT是慢查询重灾区:LIMIT 100000,20需要扫描前10万行再丢弃。优化方案有延迟关联:
-- 先只取主键再回表
SELECT t.*
FROM orders t
JOIN (SELECT id FROM orders ORDER BY id LIMIT 100000, 20) tmp
ON t.id = tmp.id
ORDER BY t.id;
时间线型数据推荐游标分页:WHERE id > last_seen_id ORDER BY id LIMIT 20,利用主键索引直接定位,恒定扫描20行。数据量更大时考虑按时间分区表,把查询范围缩到单个分区,从根上减少扫描量。
优化效果验证方法
每轮优化后用EXPLAIN对比rows预估与key列,再实际执行对比耗时,阈值建议从秒级优化到百毫秒内。线上验证用EXPLAIN ANALYZE(MySQL 8.0.18+)拿到真实执行时间与循环耗时,比rows预估更准。优化完成后保持慢查询日志开启,观察同类SQL是否回落,确认整体数据库负载(Threads_running、QPS)是否下降。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/mysql-man-cha-xun-you-hua-shi-zhan-explain-zhi-xing-ji-hua/