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 的性能之魂。

相关推荐
野犬寒鸦5 小时前
从零起步学习MySQL || 第七章:初识索引底层运用及性能优化(结合底层数据结构讲解)
java·数据库·后端·mysql·oracle
啊森要自信6 小时前
【MySQL 数据库】使用C语言操作MySQL
linux·c语言·开发语言·数据库·mysql
叫我龙翔9 小时前
【MySQL】从零开始了解数据库开发 --- 如何理解事务隔离性
数据库·mysql·数据库开发
苏小瀚21 小时前
[MySQL] 索引
数据库·mysql
Warren981 天前
复习MySQL
数据库·windows·tcp/ip·mysql·ubuntu·ssh·ansible
凌~风1 天前
数据库原理实验报告:在ider里搭建mysql数据库
数据库·mysql·实验报告
2401_841495641 天前
【数据库开发】个人信息管理的数据库创建以及查询方法(最简单)
数据库·sql·mysql·sqlite·数据库开发·个人数据库·管理个人信息
lang201509281 天前
MySQL 8.0动态TLS配置全解析
mysql
dot to one1 天前
Centos 7 环境下mysql的安装及配置
linux·mysql·centos