跳转到主要内容

MySQL 索引原理与最佳实践

B+Tree 结构、回表与覆盖索引、最左前缀原则、索引选择性,以及避免索引失效的常见写法。

索引是 MySQL 查询性能的决定性因素。理解 InnoDB 的 B+Tree 索引结构,才能写出真正命中索引的 SQL。

B+Tree 与聚簇索引

InnoDB 使用 B+Tree 组织索引,其特点是非叶子节点只存索引键用于导航,所有数据都落在叶子节点,且叶子节点通过双向链表串联,非常适合范围扫描。

InnoDB 的主键索引是聚簇索引,叶子节点直接存放整行数据;二级索引的叶子节点存放「索引键 + 主键值」。因此通过二级索引查询非索引列时,需要再用主键回表查聚簇索引。

回表与覆盖索引

当查询的列都在二级索引中时,无需回表,称为覆盖索引,性能更好:

-- idx_user_age 为 (name, age) 的联合索引
-- 仅取索引列,命中覆盖索引
SELECT name, age FROM user WHERE name = 'tom';

SELECT * 还需要 phone 等额外列,则会触发回表。高频查询应优先设计为覆盖索引。

最左前缀原则

联合索引 (a, b, c) 能生效的条件是查询从最左列开始连续匹配:

  • WHERE a = ? 可用
  • WHERE a = ? AND b = ? 可用
  • WHERE b = ? 无法使用该联合索引(断开了最左前缀)

避免索引失效

常见导致索引失效的写法:

  • 对索引列做函数运算或隐式类型转换:WHERE DATE(create_time) = ...
  • 使用前导模糊匹配:LIKE '%abc'
  • 使用 OR 连接非索引列
  • 优化器判断全表扫描更快时主动放弃索引

索引并非越多越好:每个索引都会拖慢写入与占用空间。应结合选择性(区分度)高的列建索引,并用 EXPLAIN 验证执行计划。