type=all明确表示未走索引,因优化器判定全表扫描优于索引查找,根本原因是b+树无法定位起始页,被迫线性遍历。

为什么 EXPLAIN 显示 type=ALL 就代表索引没走
因为 type=ALL 表示 MySQL 决定全表扫描,跳过了所有可用索引。这不是“可能没走”,而是明确没用——哪怕你建了 5 个索引,只要执行计划里出现 type=ALL,就说明优化器判定走索引比扫全表更慢。
根本原因在于 InnoDB 的 B+ 树搜索必须从根节点逐层下降到叶子节点,而这个过程依赖「索引列是否能被直接比较」。一旦条件破坏了这个前提(比如加函数、类型不匹配、跳过左列),B+ 树就无法定位起始页,只能退化为线性遍历。
注意:key 字段为空或显示 NULL,也佐证了未命中索引。
WHERE name LIKE '%张' 为什么 B+ 树没法加速
B+ 树的叶子节点是按索引列值**严格排序**存储的,搜索依赖“有序性”做二分查找。而 LIKE '%张' 要求匹配任意前缀 + “张”,等价于在整棵树里找所有以“张”结尾的字符串——这完全打乱了排序逻辑,MySQL 无法通过树结构剪枝,只能挨个检查每条记录。
相比之下,LIKE '张%' 可以利用前缀有序性:先定位到第一个“张”开头的值,然后向右连续读取,直到超出“张”范围,这就是 B+ 树天然支持的范围扫描。
常见误判点:
-
LIKE '%张%'同样失效,不是因为含两个%,而是因为开头通配符破坏了有序起点 -
COLLATE设置不同(如utf8mb4_binvsutf8mb4_general_ci)可能导致隐式转换,间接触发失效
WHERE age > 25 AND name = '李四' 在联合索引 (age, name) 上为何 name 部分失效
这是 B+ 树结构决定的硬约束:联合索引本质是一棵按 age 排序、age 相同时再按 name 排序的单棵树。当查询带范围条件 age > 25,MySQL 只能定位到第一个 age=26 的叶子节点,然后向右顺序扫描所有 age > 25 的记录——此时 name 已不再全局有序,无法再用树结构快速跳转。
所以 name = '李四' 这个条件只能在扫描过程中逐行过滤,不参与索引查找。
关键细节:
- 如果是
age = 25 AND name = '李四',就能精准定位单个叶子节点位置 - 如果是
age BETWEEN 25 AND 30 AND name = '李四',同样只有age段参与索引定位,name仍靠过滤 - 想让
name也生效,得把等值列放前面:索引改为(name, age),但需权衡查询模式
WHERE id = '123' 对 INT 主键索引失效的底层原因
InnoDB 看到字符串 '123' 和 INT 类型的 id 列不匹配,会自动做隐式类型转换:把 id 列每一行都转成字符串再比较。这就等于在索引列上套了一层函数,B+ 树里存的是原始整数 123,而比较时却在查 '123' 的字符串形式——二者哈希值、字节序列完全不同,无法对齐。
同理,WHERE create_time = '2024-04-21'(create_time 是 DATETIME)也会触发类似转换,因为字符串字面量需解析为时间类型,本质仍是列上加函数。
真正安全的写法:
-
WHERE id = 123(数值字面量,类型一致) WHERE create_time >= '2024-04-21' AND create_time (避免对列调用 <code>DATE())- 用
SHOW WARNINGS查看是否有Truncated incorrect DOUBLE value类提示,那是类型转换的信号











