在 MySQL 中,B+ 树是 InnoDB 存储引擎默认的索引结构。通过 B+ 树索引查询数据的过程可以分为以下几个步骤:
1. 从根节点开始
- B+ 树是一个多路平衡搜索树,查询总是从根节点开始。
- 根节点是常驻内存的(缓存在 InnoDB Buffer Pool 中),因此访问根节点不需要磁盘 I/O。
2. 逐层查找目标节点
- 从根节点开始,逐层向下查找,直到找到目标叶子节点。
- 每一层的查找过程:
- 在节点内部使用二分查找(或顺序查找)定位目标键值所在的子节点指针。
- 根据指针访问下一层的节点。
- 由于 B+ 树的节点大小通常与磁盘页大小一致(如 4KB、8KB),每次访问一个节点需要一次磁盘 I/O。
3. 定位到叶子节点
- B+ 树的所有数据都存储在叶子节点中,非叶子节点只存储键值和指针。
- 查询最终会定位到叶子节点,叶子节点中存储了完整的键值对(索引键和对应的数据指针或主键)。
4. 在叶子节点中查找目标数据
- 在叶子节点中使用二分查找(或顺序查找)定位目标键值。
- 如果查询是等值查询(如
WHERE id = 5
),找到匹配的键值后即可返回对应的数据。 - 如果查询是范围查询(如
WHERE id BETWEEN 5 AND 10
),则需要在叶子节点中遍历链表,找到所有符合条件的键值。
5. 返回查询结果
- 对于主键索引(聚簇索引),叶子节点中存储的是完整的数据行,直接返回数据即可。
- 对于二级索引(非聚簇索引),叶子节点中存储的是主键值,需要根据主键值回表查询聚簇索引,获取完整的数据行。
详细过程示例
假设有一个表 user
,其主键为 id
,并在 age
列上创建了一个二级索引。表结构如下:
CREATE TABLE user (
id INT PRIMARY KEY,
name VARCHAR(50),
age INT,
INDEX idx_age (age)
);
查询 1:通过主键查询(等值查询)
SELECT * FROM user WHERE id = 5;
- 从根节点开始:
- 访问根节点,找到
id = 5
所在的子节点指针。
- 访问根节点,找到
- 逐层查找:
- 根据指针访问下一层节点,重复查找过程,直到定位到叶子节点。
- 定位到叶子节点:
- 在叶子节点中找到
id = 5
的键值对。
- 在叶子节点中找到
- 返回数据:
- 叶子节点中存储了完整的数据行,直接返回结果。
查询 2:通过二级索引查询(等值查询)
SELECT * FROM user WHERE age = 25;
- 从根节点开始:
- 访问二级索引
idx_age
的根节点,找到age = 25
所在的子节点指针。
- 访问二级索引
- 逐层查找:
- 根据指针访问下一层节点,重复查找过程,直到定位到叶子节点。
- 定位到叶子节点:
- 在叶子节点中找到
age = 25
的键值对。
- 在叶子节点中找到
- 回表查询:
- 叶子节点中存储的是主键值,根据主键值回表查询聚簇索引,获取完整的数据行。
- 返回数据:
- 返回查询到的数据行。
查询 3:范围查询
SELECT * FROM user WHERE age BETWEEN 20 AND 30;
- 从根节点开始:
- 访问二级索引
idx_age
的根节点,找到age = 20
所在的子节点指针。
- 访问二级索引
- 逐层查找:
- 根据指针访问下一层节点,重复查找过程,直到定位到叶子节点。
- 定位到叶子节点:
- 在叶子节点中找到
age = 20
的键值对。
- 在叶子节点中找到
- 遍历链表:
- 从
age = 20
开始,沿着叶子节点的链表向后遍历,找到所有age
在 20 到 30 之间的键值对。
- 从
- 回表查询:
- 对每个符合条件的键值对,根据主键值回表查询聚簇索引,获取完整的数据行。
- 返回数据:
- 返回所有查询到的数据行。
总结
在 MySQL 的 B+ 树索引中查询数据的全过程包括:
- 从根节点开始,逐层查找目标节点。
- 定位到叶子节点,找到目标键值。
- 对于主键索引,直接返回数据;对于二级索引,需要回表查询聚簇索引。
- 对于范围查询,遍历叶子节点的链表,找到所有符合条件的键值。
B+ 树的设计使得查询时间复杂度为 O(log n),并且能够高效支持等值查询、范围查询和顺序访问,非常适合数据库的场景。
THE END
暂无评论内容