704 字
4 分钟
MySQL 索引看起来失效了,如何判断优化器的选择
  1. 1MySQL 面试复习导读:知识地图与阅读路线
  2. 2MySQL 存储引擎怎么选:InnoDB、MyISAM 与 MEMORY
  3. 3MySQL 索引类型与 B+ 树:结构、分类和失效场景
  4. 4MySQL B+ 树查询全过程:从根节点到页目录
  5. 5InnoDB 聚簇索引与二级索引:什么是回表
  6. 6MySQL 覆盖索引:如何避免回表
  7. 7MySQL 联合索引的最左前缀匹配原则
  8. 8MySQL 索引下推:把过滤提前到存储引擎
  9. 9MySQL 事务异常读:脏读、不可重复读与幻读
  10. 10MySQL 四种事务隔离级别与选型取舍
  11. 11MySQL MVCC:Undo Log、版本链与 ReadView
  12. 12MySQL InnoDB 锁的分类:行锁、表锁与意向锁
  13. 13MySQL 乐观锁与悲观锁:冲突少时重试,冲突多时排队
  14. 14MySQL 发生死锁怎么办:检测、定位与处理
  15. 15MySQL 事务的 ACID 特性分别是什么
  16. 16InnoDB Redo Log 如何保证崩溃恢复
  17. 17InnoDB Undo Log 的回滚与 MVCC 作用
  18. 18MySQL Binlog 是什么,和 Redo Log 有什么区别
  19. 19一条 MySQL 查询从连接到返回结果经历什么
  20. 20如何用 EXPLAIN 读懂 MySQL 执行计划
  21. 21MySQL 为什么需要 Redo Log 与 Binlog 两阶段提交
  22. 22MySQL 崩溃后如何恢复已提交事务
  23. 23InnoDB Buffer Pool 如何提升查询与写入性能
  24. 24联合索引应该如何设计
  25. 25InnoDB 快照读与当前读如何处理幻读
  26. 26联合索引范围条件之后的列还能使用吗
  27. 27MySQL 索引看起来失效了,如何判断优化器的选择本文
  28. 28MySQL 8.0 如何定位并处理 InnoDB 死锁
  29. 29MySQL 慢查询如何定位和优化
  30. 30MySQL 的 ORDER BY、GROUP BY 与 filesort
  31. 31MySQL 普通索引和唯一索引如何选择
  32. 32MySQL 主从复制的基本流程是什么
  33. 33MySQL 主从延迟和读写分离如何处理
  34. 34MySQL 深分页为什么慢,如何改写
  35. 35InnoDB 主键应该如何设计
  36. 36MySQL 字符集与排序规则有什么区别
  37. 37数据库范式与反范式如何取舍

MySQL 8.0 优化器根据查询条件、索引统计和代价估算选择访问计划;“字段上有索引却没走”不一定是索引失效,也可能是全表扫描更便宜。先对实际 SQL 和代表性参数运行 EXPLAIN,观察 key、type、估算 rows、filtered、Extra,再结合表规模和真实执行数据判断。

OR 与 Index Merge: WHERE a=1 OR b=2 在 a、b 各有索引时,优化器可能采用 Index Merge 合并多个索引扫描结果;也可能判断合并和回表成本更高而全表扫描。若某一侧不可索引、选择性很差或表达式复杂,OR 更可能扩大扫描。不能概括为 OR 必然让索引失效。

函数与表达式: WHERE DATE(created_at)='2026-10-01' 对索引列做函数,普通索引通常难以直接构造原列范围。可改为半开区间 created_at >= '2026-10-01' AND created_at < '2026-10-02';MySQL 8.0 也可评估函数索引或生成列索引,但需匹配表达式并考虑写入成本。

隐式类型转换: 若比较两侧类型不一致,MySQL 的转换规则可能导致索引列上的比较无法使用预期范围,实际效果取决于列类型和常量类型。例如字符串列 code 应与字符串常量比较,不要随意把列转换成数值。以执行计划和数据语义验证,不能仅凭“有转换”断言一定全表扫描。

LIKE 与选择性: LIKE 'abc%' 有机会转成范围查找;LIKE '%abc' 通常无法用普通 B+ 树定位前缀。即使条件可索引,低选择性列(如只有男女两个值)也可能因需读取大量记录而不选索引。联合索引、覆盖能力和 LIMIT 都会改变成本判断。

EXPLAIN SELECT * FROM t WHERE a=1 OR b=2;
EXPLAIN SELECT * FROM t WHERE created_at >= '2026-10-01'
AND created_at < '2026-10-02';
EXPLAIN SELECT * FROM t WHERE code = '00123';

优化应从计划异常对应的实际代价入手:更新统计信息前先确认执行计划和数据分布,再考虑 SQL 改写或索引;对比改动前后的扫描行数、延迟、写入成本。EXPLAIN ANALYZE 会运行查询,谨慎用于大表或生产高峰。

追问#

OR 条件一定不能用索引吗?#

不是。多个分支可分别走索引时,优化器可能采用 Index Merge;结果由代价模型和数据分布决定。

LIKE 'abc%' 和 LIKE '%abc' 一样吗?#

不一样。固定前缀可以形成 B+ 树范围;前导通配符通常无法定位普通索引范围。

为什么低选择性索引可能被忽略?#

若索引命中后仍需读取表中大部分行,索引扫描加回表的总代价可能高于顺序扫描。

MySQL 索引看起来失效了,如何判断优化器的选择
https://blog.xqcherry.top/posts/interview/mysql/mysql-index-optimizer-decisions/
作者
xqcherry
发布于
2026-10-12
许可协议
CC BY-NC-SA 4.0