先看explain输出的type、rows、key、extra四字段:type=all为全表扫描,rows远大于结果集说明过滤失效,key=null表示索引未被选用,extra含using filesort或using temporary表明排序或分组未走索引。

EXPLAIN 看一眼,八成问题出在没走索引、全表扫描或额外排序上。别急着加索引或改SQL,先让执行计划说话。
怎么看执行计划里哪一步拖慢了查询
在慢SQL前加 EXPLAIN,重点盯这四个字段:type、rows、key、Extra
-
type = ALL:说明正在全表扫描,哪怕只有10万行,也大概率是瓶颈 -
rows值远大于实际返回行数(比如查10条却扫50万行):过滤条件没生效,或索引没被选中 -
key = NULL:明明建了索引,但优化器没用——常见原因是WHERE里对字段用了函数,比如WHERE DATE(create_time) = '2026-08-01' -
Extra出现Using filesort或Using temporary:ORDER BY 或 GROUP BY 没走索引,MySQL被迫在内存/磁盘排序或建临时表
联合索引怎么建才真正生效
不是字段堆一起就行,顺序错了索引就废一半。核心是“最左前缀 + 等值优先 + 范围收尾”
- 等值条件(
=、IN)放最左,比如status = 1和user_id = 123,优先选区分度高的列打头 - 范围条件(
>、BETWEEN、LIKE 'abc%')只能放在等值之后,且后面字段不再走索引 - ORDER BY 字段必须紧接在WHERE条件之后,且方向一致(如
WHERE a = 1 AND b > 10 ORDER BY c DESC,索引应为(a, b, c),不是(a, c, b)) - 避免冗余索引:已有
(a, b, c),再建(a, b)就是浪费,维护成本白增
哪些写法会让索引当场失效
加了索引还慢?大概率是SQL本身绕过了索引。这些坑最常踩:
-
WHERE name LIKE '%三':前导通配符,B+树没法从左匹配,直接退化为全表扫描 -
WHERE UNIX_TIMESTAMP(create_time) > 1723400000:函数包裹索引列,优化器无法做索引下推 -
WHERE status != 0:非等值判断通常不走索引,尤其当status只有0/1两值时,优化器宁可全扫也不走索引 -
WHERE a = 1 OR b = 2:如果b没索引,整个条件就放弃索引;改成UNION或给b单独建索引更靠谱 -
SELECT *配合大OFFSET:比如LIMIT 10000, 20,MySQL仍要跳过前10000行,深度分页建议改用游标(WHERE id > last_id LIMIT 20)
慢查询日志怎么开才真正有用
光开日志没用,关键是要捕获到真实瓶颈。别只设 long_query_time = 2,线上建议调到 1 秒甚至 0.5
- 务必打开
log_queries_not_using_indexes = 1:很多“快SQL”其实没走索引,只是数据少没暴露,这个开关能揪出隐患 - 日志路径设在SSD分区,避免写慢查询日志本身成为IO瓶颈
- 定期用
mysqldumpslow或pt-query-digest分析,重点关注Count高、Query_time平均值高、Rows_examined大的SQL - 别忽略
Rows_sent和Rows_examined的比值:如果查1行却扫10万行,说明过滤逻辑或索引设计有问题
INSERT/UPDATE/DELETE 都要维护索引。真正难的不是加索引,是判断哪条SQL值得加、加在哪几个字段、顺序怎么排——这得靠 EXPLAIN 和慢日志交叉验证,而不是凭感觉。











