MySQL 慢查询定位实战:从开启慢日志到索引命中分析

举报
yd_274788088 发表于 2026/10/28 14:28:13 2026/10/28
【摘要】 从开启慢日志到 EXPLAIN 定位未命中索引的完整流程,含联合索引顺序与 EXPLAIN ANALYZE 实战。

线上接口偶发超时,第一反应往往是「加机器」,但多数情况慢在几条没走索引的 SQL 上。这篇记录一套从开启慢日志到定位具体语句的完整流程。

一、确认慢日志是否真的开着

SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
SHOW VARIABLES LIKE 'slow_query_log_file';

常见误区:以为在 my.cnf 里写了就生效,实际需要 SET GLOBAL slow_query_log = ON; 动态开启,或者重启。三个变量都确认过再往下走。

二、让慢日志记录到表里比写文件更好查

SET GLOBAL log_output = 'TABLE';
SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 20;

写文件的好处是不占库空间,但排查时要 ssh 上去 grep。写成 TABLE 可以直接用 SQL 过滤,尤其在容器化环境里省掉很多麻烦。

三、用 EXPLAIN 看索引有没有命中

EXPLAIN SELECT id, name FROM orders WHERE user_id = 123 AND status = 1 ORDER BY created_at DESC LIMIT 20;

三个关键列:

  • type:出现 ALL 就是全表扫描,ref/range 才算用上索引
  • key:实际用的索引名,为 NULL 说明没走索引
  • rows:预估扫描行数,和实际返回行数差几百倍就是索引选择性差

四、联合索引的顺序很关键

上面的查询最合适的索引是 (user_id, status, created_at),顺序不能换:

  • 等值条件放最左(user_id、status)
  • 范围/排序放最后(created_at)

如果建成 (created_at, user_id, status),因为 created_at 是排序列不是等值条件,索引基本用不上。

五、EXPLAIN ANALYZE 拿真实执行数据

EXPLAIN ANALYZE SELECT ...;

MySQL 8.0.18+ 支持,会真的执行一遍并给出每步实际耗时和行数。比 EXPLAIN 的预估值可靠得多,代价是语句会真跑,写操作慎用。

六、几个容易忽略的点

  • ORDER BY + LIMIT 在没合适索引时会先全表排序再取前 N 条,代价极高
  • 隐式类型转换会让索引失效,比如 varchar 字段用数字比较
  • 函数包裹索引列(WHERE DATE(created_at) = '2026-10-28')必然失效

定位慢查询的核心不是记住参数,而是养成「先看执行计划再改 SQL」的习惯。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。