索引基础与 B+ Tree
约 1197 字大约 4 分钟
布欧-Lewyon
2026-05-15
首页 › MySQL › 索引与性能(在新窗口打开) › 索引基础与 B+ Tree
索引(Index)是数据库加速数据检索的数据结构,类似书的目录:不必从头翻到最后一页,直接通过目录找到目标所在页码。但索引并非没有代价——它会占用额外空间,并在写入时增加维护开销。
什么是索引
没有索引时,MySQL 执行 WHERE 查询只需要全表扫描(依次读取每一行,检查是否匹配)。数据量大时,这种方式极慢。
-- 无索引时:全表扫描
SELECT * FROM employee WHERE name = '张三';
-- 需扫描所有行,O(n) 复杂度
-- 有索引时:通过索引找到行位置,直接读取
-- O(log n) 复杂度B+ Tree 数据结构
InnoDB 使用的索引结构是 B+ Tree(平衡多路搜索树)。
B+ Tree 的关键特性:
| 特性 | 说明 |
|---|---|
| 多路分支(非二叉树) | 每个节点可存储数百个键值,树高度通常为 2~4 层 |
| 数据仅存在叶子节点 | 非叶子节点只存键值和指针,不存数据 |
| 叶子节点双向链表 | 范围查询时无需回溯树,直接遍历叶子链 |
| 自平衡 | 插入/删除时通过分裂和合并保持平衡 |
为什么 B+ Tree 比二叉树更适合磁盘:
- 二叉树高度随数据量线性增长,百万级数据时树高约 20 层(log2)。
- B+ Tree 将大量键值放入一个节点(一个磁盘 Page 通常 16KB),千万级也只要 3~4 层。
- 磁盘 IO 是主要开销,3~4 次 IO 远优于 20 次。
聚簇索引(Clustered Index)
InnoDB 的表本身就是索引,数据按主键顺序存储在 B+ Tree 的叶子节点上,这种索引叫聚簇索引。
CREATE TABLE example (
id INT PRIMARY KEY, -- 聚簇索引
name VARCHAR(50),
age INT
);
-- id 是主键,InnoDB 自动以 id 建立聚簇索引
-- 叶子节点直接存储整行数据特征:
- 每个 InnoDB 表有且只有一个聚簇索引(即主键)。
- 叶子节点存储整行数据,所以"通过主键查询"一次索引即找到全部数据。
- 如果表没有定义主键,InnoDB 会选第一个
NOT NULL UNIQUE列,或隐式生成一个ROW_ID。
辅助索引(Secondary Index,二级索引/非聚簇索引)
除聚簇索引外的索引都是辅助索引。叶子节点不存数据,而是存主键值。
CREATE INDEX idx_name ON example(name);
-- 叶子节点: (name, id)
-- 查询过程:先查 idx_name 找 id,再回聚簇索引查完整数据回表:使用辅助索引查询时,先找到主键值,再到聚簇索引中取完整数据行,这个过程称为"回表"。
索引的代价
-- 建表时加过多索引
CREATE TABLE user (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
phone VARCHAR(20),
age INT,
city VARCHAR(50),
INDEX idx_name (name),
INDEX idx_email (email),
INDEX idx_phone (phone),
INDEX idx_age (age),
INDEX idx_city (city)
);| 代价 | 说明 |
|---|---|
| 空间占用 | 每个索引对应一棵 B+ Tree,占用磁盘空间 |
| 写入变慢 | INSERT/UPDATE/DELETE 每行数据时,需同步维护所有索引 |
| 内存消耗 | InnoDB Buffer Pool 要缓存热索引页,索引越多缓存压力越大 |
经验法则:单表索引数量建议控制在 5~8 个以内,写入频繁的表应更少。
何时创建索引
-- 适合建索引的场景
WHERE name = '张三' -- 经常出现在 WHERE 中
ORDER BY created_at -- 经常排序
JOIN t2 ON t1.id = t2.id -- JOIN 关联列
UNIQUE(email) -- 唯一性约束-- 不适合建索引的场景
gender ENUM('M', 'F') -- 区分度太低(基数很小)
status TINYINT DEFAULT 1 -- 只有几个值
BLOB/TEXT(除非前缀索引) -- 太长,索引体积大
低频查询的列 -- 索引维护成本超过查询收益小结
- 索引通过 B+ Tree 加速检索,千万级数据也只需 3~4 层树高。
- InnoDB 聚簇索引(主键)的叶子节点存整行数据;辅助索引存主键值,查询时需回表。
- 索引不是越多越好:占用空间、降低写入性能、消耗内存。
- 适合索引的列:高频 WHERE / JOIN / ORDER BY、高区分度。
上一节:表关系与 E-R 图 下一节:索引类型与使用策略
