B+树揭秘:MySQL索引核心原理全解析

MySQL 索引按不同维度可以分成多类,底层核心是 ‌B+ 树 ‌,配合 ‌哈希索引 ‌ 做特定场景加速,整体查询时间复杂度为 ‌**O(log N)**‌。

索引类型

  1. ‌按数据结构‌:B+ 树索引、哈希索引、全文索引(倒排索引)、空间索引(R-Tree)。
  2. ‌按物理存储‌:聚簇索引(叶子节点存整行数据,InnoDB 主键默认)和非聚簇索引(叶子节点存数据地址或主键值,MyISAM 默认)。
  3. ‌按字段特性‌:主键索引、唯一索引、普通索引、全文索引。
  4. ‌按字段个数‌:单列索引、联合索引(复合索引,遵循最左前缀原则)。‌‌

底层实现原理

‌B+ 树是 MySQL 默认且最核心的索引结构‌(InnoDB 和 MyISAM 都支持),它的设计目标就是减少磁盘 I/O:

  • ‌非叶子节点只存索引键‌,不存数据,因此单个节点能容纳大量键值,树高度很低(通常 2~4 层),查询任意数据只需少量磁盘 I/O。
  • ‌所有数据都存在叶子节点 ‌,且叶子节点通过有序链表串联,范围查询(BETWEEN、>、<)和排序效率极高,直接沿链表遍历即可。
  • ‌数据物理有序‌(聚簇索引下),InnoDB 表数据本身按主键顺序存储在 B+ 树的叶子节点上,主键查询直接定位到行数据。‌‌

‌哈希索引 ‌ 在 InnoDB 中以"自适应哈希索引"形式存在:当某个索引值被频繁访问时,InnoDB 会在 B+ 树之上自动构建哈希索引,等值查询可以 O(1) 定位,但‌不支持范围查询‌,且该过程由引擎自动管理,无法人工干预。‌‌

‌MyISAM 与 InnoDB 的关键差异 ‌:MyISAM 的索引叶子节点存的是‌数据行的物理地址 ‌,查到地址后直接取数据;InnoDB 的二级索引叶子节点存的是‌主键值‌,需要再回主键索引树查一次(回表查询)。‌‌

时间复杂度对比

引类型 等值查询 范围查询 排序 说明
B+ 树索引 O(log N) O(log N + M) 支持 M 为结果集大小,InnoDB 默认
哈希索引 O(1) 不支持 不支持 仅等值,有哈希冲突风险
全文索引 O(N) 不支持 不支持 倒排索引实现关键词匹配
无索引全表扫描 O(N) O(N) 不支持 性能最差

B+ 树查询之所以稳定在 O(log N),是因为‌树高可控‌(通常 3~4 层),百万和千万级数据量下等值查询耗时几乎一致;而哈希索引虽然等值 O(1),但无法用于范围查询和排序,所以不能作为通用索引结构。‌‌

面试/理解要点

  1. ‌为什么不用哈希做默认索引‌:等值查询虽快,但数据库高频操作是范围查询和排序,哈希完全无法支持。
  2. ‌为什么不用二叉树/红黑树‌:数据量巨大时树高过深,每次向下查找都是一次磁盘 I/O,性能急剧下降;B+ 树通过多路分支大幅降低树高。
  3. ‌聚簇索引与二级索引 ‌:InnoDB 表必有且仅有一个聚簇索引(优先主键);二级索引查询通常需要回表,‌覆盖索引‌可以避免回表,是常见优化手段。
  4. ‌联合索引最左前缀‌:复合索引查询时必须从最左列开始,否则索引失效,这是 B+ 树结构直接决定的。‌‌

MySQL 索引按不同维度可以分成好几类,底层最核心的实现是 ‌B+树‌,InnoDB 引擎下主键索引就是典型的聚簇索引。下面给你按分类讲清楚,再配个例子说明查找过程。

按数据结构分类

  1. ‌B+树索引‌:绝大多数存储引擎的默认索引类型,也是 InnoDB 和 MyISAM 最常用的实现方式。数据有序存储,支持等值、范围和排序查询。
  2. ‌哈希索引‌:能以 O(1) 时间复杂度做等值查找,但数据无序,不支持范围查询。InnoDB 有个特殊优化叫"自适应哈希索引",当某个索引值被频繁访问时,会在 B+树之上自动建一层哈希索引,兼顾两者优点。
  3. ‌全文索引 ‌:用于在文本列中查找关键词,而不是比较是否相等。底层用倒排索引实现,记录"关键词 → 所在文档"的映射,配合 MATCH AGAINST 使用。MyISAM 一直支持,InnoDB 从 MySQL 5.6.4 开始支持。
  4. ‌空间数据索引‌:用于存储地理数据,能从所有维度索引数据,支持任意维度组合查询。MyISAM 支持,MySQL 从 5.7 版本开始支持。

按应用功能分类

  1. ‌普通索引 ‌:最基本的索引,基于普通字段建立,没有任何限制,创建方式:CREATE INDEX idx_name ON table(col);
  2. ‌唯一索引‌:与普通索引类似,但索引字段的值必须唯一,允许有空值。创建或修改表时加唯一约束会自动创建对应索引。
  3. ‌主键索引‌:一种特殊的唯一索引,不允许有空值。每个表只能有一个主键,InnoDB 中它同时就是聚簇索引。
  4. ‌复合索引(联合索引) ‌:在多个列上建立的索引,如 (a, b, c)。相比多个单列索引,复合索引开销更小,但使用时必须遵循‌最左前缀原则‌------查询条件从最左列开始连续匹配才能用到索引。

按物理存储分类

  1. ‌**聚簇索引(聚集索引)**‌:叶子节点直接存储完整行数据,数据物理顺序与索引顺序一致。InnoDB 中主键索引就是聚簇索引,一个表只能有一个。如果没有定义主键,InnoDB 会选第一个非空唯一索引;再没有的话,自动生成一个 6 字节的隐藏主键。
  2. ‌非聚簇索引(二级索引/辅助索引) ‌:叶子节点不存完整行数据,只存索引字段值和主键值。通过二级索引查数据时,需要先用主键到聚簇索引里再查一次,这个过程叫‌回表‌。MyISAM 的索引叶子节点存的是数据行地址,也属于非聚簇实现。

底层实现原理举例

‌InnoDB 主键查询 ‌:假设有一张用户表 user(id, name, age),id 是主键。InnoDB 会把整张表按主键 id 构建成一棵 B+树,树的叶子节点就是完整的数据行。当执行 SELECT * FROM user WHERE id = 5 时,从根节点开始二分查找,约 2---3 次磁盘 I/O 就能定位到叶子节点直接取出整行数据,速度非常快。

‌二级索引回表查询 ‌:如果给 name 建了普通索引,会再生成一棵 B+树,叶子节点存的是 (name, id)。执行 SELECT * FROM user WHERE name = '张三' 时,先在这棵二级索引树里找到 id,再用 id 到主键聚簇索引树里查完整行数据------这就是回表。如果只查 SELECT id FROM user WHERE name = '张三',二级索引里已经有 id,不需要回表,这种情况叫‌覆盖索引‌,效率更高。

‌为什么选 B+树而不是其他结构‌:数据库的瓶颈在磁盘 I/O。二叉树或红黑树每个节点只能存一个 key,数据量大时树很高,查询要多次 I/O;B树虽然能存多个 key,但非叶子节点也存数据,单个节点能容纳的 key 数量有限。B+树的非叶子节点只存索引不存数据,同样大小的节点能存更多 key,树更矮(千万级数据通常 3 层),一次查询只需 2---3 次磁盘 I/O;而且叶子节点用链表串起来,范围查询和排序遍历非常高效。‌‌

使用建议

  1. ‌主键尽量用自增整型‌,避免用 UUID 等随机值。随机主键会导致频繁页分裂和碎片,自增主键顺序写入效率最高。
  2. ‌复合索引遵循最左前缀原则 ‌,比如建立了 (a, b, c) 索引,查询条件里有 a 和 c 但缺 b,只有 a 能用上索引。
  3. ‌索引不是越多越好‌,每个索引都要额外占用存储空间,还会拖慢插入、更新和删除操作。
相关推荐
余槐i3 小时前
MySQL 深分页从 4 秒到 60 毫秒:延迟关联减少回表的实测与代价
mysql·性能优化·sql优化·执行计划·慢查询优化
PHP实战开发录6 小时前
MySQL字段加索引为什么没变快
数据库·mysql·php·开发
天衍四九-6 小时前
【无标题】
前端·spring boot·mysql·nginx·docker
蛋蛋的就会顺顺的6 小时前
hot100——矩阵
java·数据结构·算法·leetcode·力扣
Lysander.Jovian7 小时前
mysql数据库基本使用
mysql
Shadow(⊙o⊙)7 小时前
MySQL索引
数据库·mysql
学代码的CJY7 小时前
从代码出发理解时间复杂度与空间复杂度
数据结构·算法
fb_123458 小时前
MySQL运维实战:备份恢复+主从复制+读写分离+MHA高可用(超详细手把手教程)
运维·mysql·oracle
字节跳动的猫9 小时前
LikeShop 积分体系全链路改造:获取规则、订单抵扣与积分商品兑换二开
运维·数据结构