MySQL 的 B+ 树中查询数据的全过程

📌 MySQL 的 B+ 树索引如何查询数据?

在 MySQL 的 InnoDB 存储引擎中,索引采用 B+ 树(B+ Tree) 结构。B+ 树索引的查询过程涉及 磁盘 IO、缓冲池、事务日志(redo log)和 MVCC 等多个环节。下面详细解析 MySQL 使用 B+ 树索引查找数据的全过程


🧩 1. B+ 树索引结构

🔹 B+ 树的基本特点

  1. 多路平衡查找树

    • 每个节点存多个 索引值(key),多个 指向子节点的指针(pointers)。
    • 非叶子节点只存索引值,不存数据。
    • 叶子节点存索引值 + 真实数据,并通过 双向链表 连接,方便范围查询。
  2. 磁盘 IO 友好

    • 非叶子节点存大量索引,减少树的高度,降低查询时的磁盘 IO 次数。
  3. 范围查询高效

    • 叶子节点的链表结构,使得 B+ 树能高效进行顺序扫描(适用于 BETWEENORDER BY 查询)。

🔍 2. B+ 树索引的查询过程

假设有如下 users 表,并且 id 字段上有 B+ 树索引

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    age INT
);

数据如下:

idnameage
1Alice25
5Bob30
10Carol28
15David35
20Ellen40

B+ 树索引结构如下:

       [ 5   15 ]
      /        \
[1, 5]      [10, 15, 20]

查询 SQL:

SELECT * FROM users WHERE id = 10;

🚀 查询流程

  1. 客户端发送 SQL 语句

    • MySQL 解析 SQL,判断 id 字段是 主键索引(聚簇索引)。
    • 进入查询优化器,选择 B+ 树索引查询。
  2. 在 B+ 树中查找 id = 10

    • 第一层(根节点):[5, 15]
      • 10 > 5,但 10 < 15,沿着 5 的右指针 进入下一层。
    • 第二层(叶子节点):[10, 15, 20]
      • 找到 id = 10,获取完整行数据。
  3. 查询缓存(Buffer Pool)

    • MySQL 先从 Buffer Pool(缓冲池) 查找是否已加载该数据页:
      • 如果数据页在缓存中,直接返回(避免磁盘 IO)。
      • 如果数据页不在缓存中,从 磁盘 读取数据页,加载到缓存(LRU 机制)。
  4. 返回查询结果

    • MySQL 执行完成后,将数据返回给客户端。

🎯 3. 详细的 B+ 树磁盘 IO 过程

🧱 磁盘页(Page)

MySQL 采用 磁盘分页(Page) 方式存储数据,默认 每页 16KB

查询 id = 10 时的磁盘 IO

  1. 读取根节点(索引页)
    • 该页可能已缓存在 Buffer Pool 中,如果不在,执行一次 磁盘 IO 读取。
  2. 读取叶子节点(数据页)
    • 如果数据页不在缓存,需要执行 第二次磁盘 IO 读取该页。

一般来说,一次查询只需要 1~3 次磁盘 IO(树高一般为 2~3 层)。


📝 4. B+ 树查询 vs. 全表扫描

🔹 使用索引查询

EXPLAIN SELECT * FROM users WHERE id = 10;

输出:

+----+-------------+-------+-------+---------------+---------+---------+-------+
| id | select_type | table | type  | possible_keys | key     | rows    | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+
|  1 | SIMPLE      | users | const | PRIMARY       | PRIMARY | 1       | NULL  |
+----+-------------+-------+-------+---------------+---------+---------+-------+
  • type = const(表示使用索引查找,性能高)
  • rows = 1(只查找一条数据)

🔹 全表扫描(没有索引时)

EXPLAIN SELECT * FROM users WHERE name = 'Alice';

输出:

+----+-------------+-------+------+---------------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key  | rows    | Extra       |
+----+-------------+-------+------+---------------+------+---------+-------------+
|  1 | SIMPLE      | users | ALL  | NULL          | NULL | 1000000 | Using where |
+----+-------------+-------+------+---------------+------+---------+-------------+
  • type = ALL(表示全表扫描,性能低)
  • rows = 1000000(可能遍历百万级数据)

结论: ✅ 使用 B+ 树索引能显著减少扫描行数,提高查询效率。


📌 5. 范围查询

B+ 树的 叶子节点通过链表连接,因此范围查询比 B-树更快:

SELECT * FROM users WHERE id BETWEEN 5 AND 15;

查询流程:

  1. B+ 树中定位 id = 5 的叶子节点
  2. 沿着叶子节点的链表,顺序遍历到 id = 15,返回数据。

🔹 范围查询高效的原因

  • B+ 树的叶子节点链表结构,可以高效顺序扫描。
  • 磁盘预读优化,一次读取多个数据页,减少磁盘 IO。

✅ 6. 总结

🛠 MySQL B+ 树索引查询过程

  1. SQL 解析:优化器选择索引(如 PRIMARY)。
  2. B+ 树查找
    • 根节点 开始查找索引值所在范围。
    • 进入 叶子节点 读取完整数据行。
  3. Buffer Pool 缓存
    • 如果数据页已缓存,避免磁盘 IO。
    • 如果不在缓存,触发 磁盘 IO 读取 数据页。
  4. 返回查询结果

🚀 为什么 MySQL 选择 B+ 树?

  1. 磁盘 IO 友好:降低树高(一般 ≤3),减少 IO 次数。
  2. 范围查询高效:叶子节点链表结构,顺序读取快。
  3. 索引节点存储密度高:一个节点存多个索引,减少查询层数。

📌 结论

MySQL B+ 树索引使得查询速度接近 O(log N),远优于全表扫描 O(N)。通过 Buffer Pool 缓存、磁盘 IO 预读 进一步优化查询性能,确保高效的数据库查询。🚀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值