1. B+Tree 是 MySQL 中最核心的索引结构
B+Tree 结构特点
- 多叉平衡树;
- 所有数据都在 叶子节点;
- 叶子节点之间 按顺序链表连接;
- 非叶子节点只存 索引键 + 指针
为什么 MySQL 用 B+Tree:
- 磁盘 IO 次数少 , B+Tree 高度很低;
- 非常适合范围查询 , 因为叶子节点有 链表
- 支持排序, 因为叶子节点 天然有序
- 支持最左前缀匹配
2. B+Tree 与 Hash 索引的区别
Hash 索引特点
- 优点
- 查询速度非常快
- 等值查询极佳
- 缺点
- 不支持范围查询
- 不支持排序
- 不支持最左匹配
InnoDB 的自适应 Hash
- InnoDB 会自动把 热点 B+Tree 查询转为 Hash
- Adaptive Hash Index (AHI)
3. MySQL 索引底层
MySQL 索引底层:
B+Tree Hash R-Tree
但 生产环境 95% 都是 B+Tree。
原因:
B+Tree 同时支持
等值查询 范围查询 排序 索引扫描
MySQL索引底层主要使用 B+Tree、Hash、R-Tree 三种数据结构,其中 B+Tree 是最核心的实现,InnoDB 和 MyISAM 的普通索引与主键索引基本都是 B+Tree;Hash 索引用于 Memory 引擎和 InnoDB 的自适应 Hash;R-Tree 用于 GIS 空间索引。
4. 为什么 MySQL 选择 B+Tree 而不是红黑树
索引选择 B+Tree 而不是 红黑树,核心原因是:数据库索引主要面对磁盘 IO,而不是纯内存操作。B+Tree 在 磁盘访问模式、范围查询、树高度控制 等方面明显更适合数据库场景。
数据库索引设计必须优化三个关键指标:
- 1️⃣ 减少磁盘 IO
- 2️⃣ 支持范围查询
- 3️⃣ 支持排序扫描
所以数据库设计目标是:尽量减少树的高度,从而减少磁盘访问次数
数据库读取数据是 按页(Page)读取。在 InnoDB 中:Page Size = 16KB ; B+Tree 节点 刚好就是一个 Page。 例如:16KB / 16B ≈ 1000 个 key; 所以一个节点可以存:≈1000 个索引 而红黑树:一个节点只存一个 key; 导致:大量磁盘 IO 浪费
红黑树结构:中序遍历才能获得有序数据; 需要 频繁跳跃访问节点。磁盘访问效率非常差。
MySQL 选择 B+Tree 而不是红黑树的主要原因是数据库索引需要减少磁盘 IO。红黑树是二叉结构,树高度较高,查询时需要多次磁盘访问;而 B+Tree 是多路平衡树,一个节点可以存储大量 key,使树高度非常低,通常 3~4 层即可存储上亿数据,从而大幅减少磁盘 IO。同时 B+Tree 的叶子节点通过链表连接,非常适合范围查询和排序扫描,因此数据库索引普遍采用 B+Tree 结构。
5. B-Tree 与 B+Tree 的结构区别
B-Tree 的特点:
- 所有节点都存储 key 和数据
- 每个节点都可能是最终数据节点
- 查找可能在任意层结束
B+Tree 的特点:
- 非叶子节点只存 key
- 数据全部在叶子节点
- 叶子节点之间有链表
MySQL 选择 B+Tree 而不是 B-Tree 的主要原因是 B+Tree 更适合数据库的磁盘访问模式。B+Tree 的内部节点只存储 key 和指针,使得每个节点可以存储更多 key,从而降低树的高度,减少磁盘 IO。同时 B+Tree 的所有数据都在叶子节点,并且叶子节点通过链表连接,非常适合范围查询和顺序扫描。因此数据库系统普遍采用 B+Tree 作为索引结构。
6. 聚簇索引
聚簇索引是指 索引结构和数据行存储在一起,也就是说 B+Tree 的叶子节点直接存储整行数据
在 InnoDB 中:主键索引就是聚簇索引
表的数据 按照主键顺序存储在 B+Tree 中 换句话说:索引 = 数据 而不是:索引 → 指向数据
聚簇索引的叶子节点就是数据页
聚簇(Clustered)”的含义是:数据行按索引顺序聚集在一起
除了主键索引,还有:
- 普通索引
- 唯一索引
- 联合索引
这些叫:Secondary Index(二级索引)
二级索引的叶子节点存什么? 在 InnoDB 中:二级索引叶子节点存储的是:索引列 + 主键值 而不是:索引列 + 数据地址
一张表只能有一个聚簇索引,因为:数据只能按一种顺序存储
在 InnoDB 存储引擎中,一张表只能有一个聚簇索引。聚簇索引通常是主键索引,如果表没有主键,则会选择第一个 UNIQUE NOT NULL 索引作为聚簇索引;如果也没有这样的索引,InnoDB 会自动生成一个隐藏的 6 字节 row_id 作为聚簇索引。MySQL 不能直接创建聚簇索引,通常是通过定义 PRIMARY KEY 来设置聚簇索引。