数据库索引常用 B+ 树解释:内部节点用于定位子树,叶子节点保存索引记录;叶子之间的有序连接便于连续扫描。它通过较大的分支数降低树高,让查找不必逐条扫描全部记录。
B 树与 B+ 树的差别
在常见的抽象定义中,B 树的内部节点也可以保存数据记录;B+ 树把数据条目集中在叶子层,内部节点主要保存分隔键和子节点指针。
这种结构有两个直观好处:内部节点能容纳更多导航项,范围查询定位起点后可以顺序访问后续叶子。但“叶子保存什么”仍取决于存储引擎,不能统一说成“所有索引的叶子都只有行地址”。
InnoDB 聚簇索引的叶子保存行
InnoDB 将行数据组织在聚簇索引中。选择规则依次是:
- 有主键时,使用主键。
- 没有主键时,选择所有列均为 NOT NULL 的第一个 UNIQUE 索引。
- 都没有时,生成内部隐藏行 ID 对应的聚簇索引。
二级索引记录则包含二级索引列和对应的主键列值,后者用于定位聚簇索引中的行。因此,“二级索引叶子只存主键”并不准确。较长的主键也会增加二级索引的存储成本。MySQL 8.0:聚簇索引和二级索引
覆盖查询和回表
设表有主键 id,另有 email 索引:
CREATE TABLE index_demo (
id BIGINT PRIMARY KEY,
email VARCHAR(200) NOT NULL,
display_name VARCHAR(100),
INDEX idx_email (email)
) ENGINE=InnoDB;
下面两种查询需要的数据不同:
EXPLAIN SELECT id, email
FROM index_demo WHERE email = 'reader@example.com';
EXPLAIN SELECT display_name
FROM index_demo WHERE email = 'reader@example.com';
第一条需要的列可以被 idx_email 覆盖;第二条需要索引中没有的 display_name,通常还需通过主键访问聚簇索引,也就是常说的回表。具体访问路径仍以执行计划和运行条件为准;覆盖列并不是对底层所有行访问行为的绝对保证。
以上是结构示例,应在自己的测试库使用,不代表某个线上表的实际执行结果。
不能用树高直接换算容量
“三层一定能存多少 GB”没有通用答案。页大小、键宽、行宽、页填充率都会改变节点能容纳的条目数;聚簇索引的叶子还是实际行,不能套用纯指针节点的容量。
理解时可以先估计每个内部页的分支数,再估计叶子页数量和每页记录数。树高决定导航层数,却不等于每次查询都发生同样次数的磁盘读取,因为缓存、范围扫描和回表都会影响实际成本。
设计索引时,先看查询条件、排序和返回列,再看索引宽度与维护成本,比记住一个固定树高或容量数字更有用。