mysql索引底层采用b+树,因其专为磁盘i/o优化:节点大小匹配磁盘块(16kb),非叶节点仅存键和指针以提升扇出,2000万行数据通常仅需3层、3次io;叶子节点双向链表支持高效范围查询;聚集索引叶子存整行数据,二级索引需回表;联合索引遵循最左前缀原则;索引过多会增加写操作开销与维护成本。

MySQL 的索引底层用的是 B+树,不是 B 树,也不是二叉树或哈希表。它专为磁盘 I/O 优化设计,核心目标是:用尽可能少的磁盘读取次数,快速定位数据。
B+树为什么被选作 MySQL(InnoDB)索引结构
因为磁盘读写是数据库最慢的一环,而 B+树能最大限度减少磁盘 IO 次数:
- 每个节点大小默认为 16KB,刚好匹配一次磁盘块读取,一次 IO 就能加载完整节点
- 非叶子节点只存“键值 + 子节点指针”,不存真实数据,所以单个节点能容纳更多索引项(比如主键为 BIGINT,加指针约 14 字节,16KB 可存约 1170 个键)
- 树高度极低:2000 万行数据,通常只需 3 层 B+树(根 → 中间层 → 叶子),最多 3 次磁盘 IO 就能查到任意一条记录
- 所有叶子节点用双向链表串起来,范围查询(如
WHERE id BETWEEN 100 AND 200)时,找到起点后可顺序遍历,无需反复回溯父节点
聚集索引 vs 二级索引:数据怎么放
InnoDB 表有且仅有一个聚集索引(Clustered Index),它的叶子节点直接存整行数据;其他索引都叫二级索引(Secondary Index),叶子节点只存“索引列值 + 对应的主键值”:
- 如果表有主键,聚集索引就是主键索引,数据按主键物理排序存放
- 没主键时,InnoDB 自动生成隐藏的
row_id作为聚集索引键 - 二级索引查数据要“回表”:先通过二级索引找到主键值,再用该主键去聚集索引里查整行 —— 这就是为什么覆盖索引(索引里已含 SELECT 所需字段)能避免回表、提升性能
联合索引与最左前缀原则
联合索引本质上还是 B+树,只是排序规则变成“先按第一列升序,相同时按第二列升序,以此类推”:
- 只有查询条件包含最左连续列时,索引才生效。例如索引
(a, b, c),WHERE a=1 AND b=2可用,WHERE b=2 AND c=3就无法使用 - 范围查询(
>、、<code>BETWEEN)会中断后续列的索引利用。比如WHERE a=1 AND b>2 AND c=3,c 列就用不上索引 - 等值 + 范围 + 排序组合常见,B+树天然支持:等值列用于快速定位子树,范围列在子树内扫描,排序列则因数据已有序而免排序
索引不是越多越好:B+树的维护成本
每次 INSERT/UPDATE/DELETE 都可能触发 B+树节点分裂或合并:
- 插入导致页满时,会分裂成两个页,并向上更新父节点;极端情况树高 +1
- 删除后若页填充率低于 50%,可能触发合并,释放空间
- 索引越多,写操作越慢,占用磁盘空间越大,优化器选择执行计划也更复杂
基本上就这些。B+树不是黑盒,理解它怎么组织数据、怎么查找、怎么维护,才能写出高效 SQL,也才能真正看懂 EXPLAIN 输出里的 key_len、rows、Extra 含义。










