MySQL 8 索引与 B+ 树-初浅理解

一、为什么要理解索引结构?

我们平常写下的 SQL:

sql 复制代码
SELECT * FROM user WHERE id = 100;

虽然只是一行查询语句,但 MySQL 背后是如何"知道"该去哪一页找数据的?

为什么即使有上千万行,也能瞬间查到?

核心答案只有三个字:B+ 树


二、索引的本质是什么?

在 InnoDB 引擎中:

  • 索引(Index)不是"附加文件",而是数据的有序组织结构
  • MySQL 通过 B+ 树(Balanced Plus Tree) 实现高效查找;
  • 所有表数据都存储在主键 B+ 树的叶子节点中。

一张表,其实就是一棵以主键为索引的 B+ 树。


三、建表示例

sql 复制代码
CREATE TABLE A (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50),
  age INT
) ENGINE=InnoDB;
  • id 是主键;
  • MySQL 自动为它建立聚簇索引(Clustered Index)。

四、插入数据:B+ 树的起点

sql 复制代码
INSERT INTO A (name, age) VALUES ('Tom', 18);
INSERT INTO A (name, age) VALUES ('Jerry', 22);

表中数据:

id name age
1 Tom 18
2 Jerry 22

初始结构(单页)

ini 复制代码
┌────────────────────────────────┐
│  Root/Leaf Page(同一个页)     │
│--------------------------------│
│ id=1 | name=Tom | age=18        │
│ id=2 | name=Jerry | age=22      │
└────────────────────────────────┘

只有一个页(Page),所有数据都在这个叶子页中。


五、页分裂:B+ 树如何"长大"

InnoDB 的每个数据页大小为 16KB

一行约 60 字节,一个页能存 约 270 行

当插入第 271 行时,页满了,触发 页分裂(Page Split)


分裂前

bash 复制代码
Page#1
┌─────────────────────────────┐
│ id=1 ~ id=270               │
│ (已满)                      │
└─────────────────────────────┘

分裂后

ini 复制代码
           Root Page
           ┌───────────────┐
           │ key = 135     │
           └───────────────┘
              /         \
             /           \
┌────────────────┐   ┌────────────────┐
│ Page#1: id 1~135 │   │ Page#2: id 136~270 │
└────────────────┘   └────────────────┘

此时树高 = 2 层(Root + Leaf)。


六、数据继续增长:形成三层结构

当页越来越多时,Root 页也可能装不下所有指针,

此时会再次分裂,形成 3 层结构。

less 复制代码
                     Root
                  (Level 3)
                     │
     ┌───────────────┴───────────────┐
     ▼                               ▼
 Internal Page#10               Internal Page#20
     │                               │
     ▼                               ▼
┌────────────┐                 ┌────────────┐
│Leaf Page#1 │──▶ ... ──▶│Leaf Page#N │
└────────────┘                 └────────────┘
  • Root:保存中间节点指针
  • Internal Node:保存页号范围
  • Leaf Node:保存完整行数据
  • 所有 Leaf 之间用双向链表连接,便于范围查询。

七、普通索引(二级索引)结构

再创建一个索引:

sql 复制代码
CREATE INDEX idx_name ON A(name);

生成一棵独立的 B+ 树(存储 name 和对应主键 id):

bash 复制代码
         idx_name(二级索引)
                 Root
                  │
       ┌──────────┴──────────┐
       ▼                     ▼
   name=Jerry,id=2      name=Tom,id=1

二级索引的叶子节点不存整行数据,只存"索引列 + 主键 id"。

当用 name 查找时,需要回表


回表示意

sql 复制代码
SELECT * FROM A WHERE name = 'Tom';

执行过程:

  1. 在 idx_name 树查 name='Tom' → 得到 id=1
  2. 去主键树查 id=1 → 获取完整行
ini 复制代码
idx_name树: name='Tom' → id=1
         ↓
主键树: id=1 → (Tom, 18)

八、B+ 树查找过程

以三层结构为例:

css 复制代码
           [Root]
             │
         ┌───┴───┐
         ▼       ▼
    [Internal] [Internal]
         │
         ▼
      [Leaf Pages]

查找 id=900000 时:

  1. 从 Root 判断区间;
  2. 进入对应的 Internal Page;
  3. 定位到 Leaf Page;
  4. 顺序扫描到匹配记录。

全程仅需 3 次磁盘 I/O(树高 3)。


九、页分裂与性能影响

插入模式 分裂频率 碎片 性能
自增主键 极少 ✅ 最优
随机 UUID 频繁 ❌ 慢
批量插入 可控 👍 稳定

建议使用自增主键,保证插入顺序、减少分裂与碎片。


十、百万级数据的树高度

层级 每节点页数 可容纳行数
叶子页 270 行 270
第二层 1000 页 27 万
第三层 1000 页 2.7 亿

百万级数据时,树高通常只有 3 层。

查找只需 3 次磁盘 I/O。


十一、整体结构回顾图

css 复制代码
                   [Root]
                     │
    ┌────────────────┴────────────────┐
    ▼                                 ▼
[Internal#1]                    [Internal#2]
    │                                 │
    ▼                                 ▼
[Leaf#1] ⇄ [Leaf#2] ⇄ ... ⇄ [Leaf#N]
  • Root:索引入口
  • Internal:保存页指针
  • Leaf:存放整行数据
  • 叶子之间用双向链表连接(便于范围扫描)

十二、总结

概念 说明
聚簇索引 表数据即索引叶子
二级索引 需通过主键回表
页分裂 数据页满后自动拆页
B+ 树高度 通常 3~4 层即可支持亿级数据
自增主键 能保持索引有序、减少分裂

十三、一句话总结

在 MySQL 8 中,索引不是"附加文件",

而是数据本身的有序存储结构。

理解 B+ 树结构,就理解了 MySQL 的性能之魂。

相关推荐
2301_7813925233 分钟前
MySQL格式化数据展示——分页查询
java·数据库·mysql·性能优化
heze091 小时前
sqli-labs-Less-23
数据库·mysql·网络安全
独自破碎E2 小时前
MySQL是怎么实现事务的?
数据库·mysql
卜锦元2 小时前
Docker Compose 部署 MySQL 8.4 LTS(生产级实践方案)
数据库·mysql·docker·容器
Smile_微笑2 小时前
恢复 MySQL 服务(Docker 环境专用)
mysql·adb·docker
卜锦元3 小时前
Docker Compose 部署 MySQL 5.7(生产级实践方案)
数据库·mysql·adb·docker
\xin3 小时前
SQL 注入、文件上传绕过、MySQL UDF 提权、SUID 提权、Docker 逃逸,以及 APT 持久化技术渗透测试全流程第二次思路
sql·mysql·docker·容器·渗透测试·json·漏洞
小北方城市网4 小时前
Spring Boot 接口开发实战:RESTful 规范、参数校验与全局异常处理
java·jvm·数据库·spring boot·后端·python·mysql
洛_尘5 小时前
MySQL 5:增删改查操作
数据库·mysql