MySQL中说的“B树索引”实际是B+树索引,因B+树所有数据存于叶子节点、叶子间有双向链表、查询路径固定,更适配磁盘I/O与范围查询;主键索引叶子存整行,二级索引叶子存列值+主键,需回表;函数、隐式转换、前导模糊匹配等会使索引失效。

MySQL 中说的“B树索引”,实际指的是 B+树索引,这是 InnoDB 和 MyISAM 存储引擎默认采用的索引结构。虽然官方文档和用户常统称其为“B树索引”,但底层实现严格来说是 B+树——它在磁盘 I/O 效率、范围查询和顺序访问方面比经典 B 树更适配数据库场景。
为什么 MySQL 用的是 B+树,不是 B 树?
核心原因在于数据库运行在磁盘上,而磁盘读写以“页”(page)为单位(InnoDB 默认 16KB)。B+树做了三项关键优化:
- 所有数据都存放在叶子节点,非叶子节点只存索引键(key),不存行记录指针或真实数据 → 同样大小的页能容纳更多 key,树更“矮胖”,高度通常 ≤3 层
- 叶子节点之间用双向链表相连 → 支持高效范围查询(如
WHERE id BETWEEN 100 AND 200)和顺序扫描(ORDER BY) - 每次查找必走到底层叶子节点 → 查询路径长度固定,性能更稳定(不像 B 树可能在中间层就命中数据)
B+树索引怎么定位一条记录?
以主键索引为例(即聚集索引):
- 从根节点开始,按 key 大小做类似二分的比较,决定往哪个子节点走
- 逐层下探,直到抵达叶子节点
- 在叶子节点中精确匹配 key,拿到对应的数据页地址和行偏移量
- InnoDB 直接读取该页中的完整行记录(因为主键索引的叶子节点存的就是整行数据)
整个过程最多只需 2~3 次磁盘 I/O(取决于数据量),远优于全表扫描的 O(n) 成本。
普通索引(二级索引)和主键索引有什么区别?
关键差异在叶子节点存储内容:
- 主键索引(聚集索引):叶子节点存完整的数据行(聚簇方式组织数据)
- 普通索引(二级索引):叶子节点只存索引列值 + 对应主键值(不是物理地址);查到主键后,还需回表一次,用主键再去聚集索引里查完整行
比如建了 INDEX idx_name ON users(name),执行 SELECT * FROM users WHERE name = 'Alice' 就会先走二级索引找到主键 ID,再拿这个 ID 去主键索引里捞整行——这叫“回表查询”。若只查 SELECT id, name,且索引已覆盖,则无需回表(覆盖索引优化)。
什么时候 B+树索引会失效?
即使建了索引,以下情况仍可能导致全表扫描:
- 对索引列使用函数或表达式:
WHERE YEAR(create_time) = 2025 -
隐式类型转换:
WHERE phone = 13800138000(phone 是 VARCHAR,数字会触发转换) - 模糊查询前导通配符:
WHERE name LIKE '%li'(无法利用索引的有序性) - OR 条件中部分字段无索引:
WHERE a = 1 OR b = 2,若 b 列没索引,可能放弃整个索引 - 索引列参与计算:
WHERE score * 2 > 100
这些本质上都破坏了 B+树按 key 有序遍历的能力,使优化器选择放弃索引。










