Files
autumn-recruitment/02.MySQL/index/B+树索引原理_test.md
T

154 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [test/review, mysql, bplus-tree, clustered-index, secondary-index]
create time: 2026-08-09 12:00
---
# B+树索引原理_测试题
## 概述
本测试涵盖 InnoDB B+树索引的核心概念,包括 B 树与 B+树的本质差异、页分裂/合并机制、聚簇索引与非聚簇索引的区别,以及联合索引设计原则。共 10 道题:6 道选择题、3 道填空题、1 道简答题。
---
## 一、选择题(6道,由浅入深)
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
### Q1(基础)— 考察定义层面
InnoDB 存储引擎默认使用的索引数据结构是什么?
A. 哈希表
B. B+树
C. 红黑树
D. 跳表
### Q2(基础)→ 考察行为差异
以下关于 B 树和 B+树的说法中,正确的是哪一项?
A. B 树的非叶子节点也存储数据记录
B. B+树的查询路径长度不一致,取决于数据位置
C. B 树的叶子节点通过链表连接,支持高效范围查询
D. B+树在同样大小的页中能容纳更多键,因此树更高
### Q3(进阶)→ 考察原理理解
假设一个 InnoDB 表的页大小为 16KB,每条索引记录约 1KB,则单个页大约能容纳多少条索引键?在此条件下,1 亿行数据的 B+树高度通常是多少层?
A. 约 16 条,树高 5~6 层
B. 约 16384 条,树高 3~4 层
C. 约 1024 条,树高 4~5 层
D. 约 100 条,树高 6~7 层
### Q4(进阶)→ 考察比较辨析
为什么推荐使用自增 BIGINT 而非 UUID 作为主键?以下解释最准确的是:
A. UUID 太长,导致 InnoDB 无法为其建立索引
B. 所有二级索引叶子节点都存储了主键值,UUID 乱序插入会导致频繁页分裂且二级索引体积庞大
C. UUID 不唯一,可能产生主键冲突
D. 自增主键的查询速度是 UUID 的两倍以上
### Q5(深入)→ 考察场景推理
某业务表的主键为自增 BIGINT,当前填充率已达 85%。此时大量并发 INSERT 导致的页分裂策略是:
A. 每次都是严格的二分平分
B. 首次分裂占 7/8,后续改为平分,以预留碎片空间
C. 只有根节点满时才向上分裂,子节点不会立即分裂
D. 先删除旧数据再合并,避免产生碎片
### Q6(深入)→ 考察源码级细节
在二级索引的叶子节点中,实际存储的内容是:
A. 完整行数据
B. 索引列的值 + 回滚指针(rollback pointer)
C. 索引列的值 + 主键值
D. 索引列的值 + 该行的物理磁盘地址
---
## 二、填空题(3道)
### F1 — 聚簇索引的定义
InnoDB 中被称为"聚簇索引"的实际上是______索引,也就是说数据和索引存储在同一个______中。一张表有且仅有______个聚簇索引。
> **提示**: 聚簇的含义指的是数据文件本身就是按 B+Tree 组织的一份索引结构,想一想哪个索引直接包含了整行数据。
### F2 — 页分裂规则
当父节点也已满时,页分裂会______向上进行,直到找到不满的父节点或到达根节点。如果根节点发生分裂,则树的______会增加 1。
> **提示**: 分裂是从叶子节点向上传递的,根节点分裂是树结构变化的一个重要标志。
### F3 — 联合索引设计
在设计复合索引 `(col1, col2, col3)` 时,区分度高的列应放在______;等值查询列应在范围查询列之______;若 `WHERE col1 = 'a' AND col2 > 10 AND col3 = 'b'`,则只有前______列能有效利用索引过滤。
> **提示**: 回忆最左前缀原则和范围查询断链陷阱——遇到范围查询时,后面的列就无法使用前缀匹配了。
---
## 三、简答题(1道)
### S1
某电商订单表 `orders` 有以下字段:`id`(BIGINT 自增主键)、`user_id`、`status`、`created_at`、`amount`。现有以下两个高频查询:
```sql
-- 查询 1:按用户查订单列表
SELECT id, status, created_at FROM orders WHERE user_id = 100 ORDER BY created_at DESC;
-- 查询 2:统计各状态的订单总数
SELECT status, COUNT(*) FROM orders GROUP BY status;
```
请综合分析:
1. 为这两个查询分别设计索引方案
2. 解释为什么要这样设计(考虑区分度、最左前缀、覆盖索引等因素)
3. 说明这种设计对 INSERT/UPDATE 操作可能带来的影响
> **答题框架提示**: 先分析每个查询的过滤条件和排序需求 → 判断哪些列适合做联合索引 → 评估是否覆盖所有 SELECT 列 → 考虑索引维护成本。
---
## 参考答案与解析
### 选择题答案
| 题号 | 正确答案 | 解析 |
|------|---------|------|
| Q1 | B | InnoDB 的默认索引结构是 B+树。哈希表不支持范围查询;红黑树是多路平衡树但在磁盘 IO 场景下不如多路树高效;跳表主要用于内存场景。 |
| Q2 | A | B 树的每个节点都存储数据和键,而 B+树的非叶子节点只存键不做数据负担,所以 A 正确。B 错误因为 B+树所有查询路径等长;C 错误因为 B 树叶节点没有链表连接;D 错误因为 B+树同样数据量下树更矮而非更高。 |
| Q3 | B | 16KB / 1KB ≈ 16 条是错误的估算方式——实际上索引键通常远小于 1KB,加上指向子节点的指针后每页可放下约 16000+ 个键。以每页约 1000~2000 个键计算,1 亿行数据的树高通常在 3~4 层。 |
| Q4 | B | 核心原因有二:① UUID 长度 36 字节,远大于 BIGINT 的 8 字节,导致所有二级索引体积膨胀,内存缓存命中率下降;② UUID 随机性导致插入顺序无序,引发频繁的页分裂和碎片。A 错在 InnoDB 可以为 UUID 建索引;C 错在 UUID 设计保证全局唯一;D 无依据。 |
| Q5 | B | InnoDB 采用"首次分裂占 7/8,后续平分"的策略来预留碎片空间,避免频繁分裂。这是面试常考的优化细节。A 错在不是严格二分;C、D 描述的策略不存在于 InnoDB 实现中。 |
| Q6 | C | 二级索引叶子节点存储的是(索引列的值 + 主键值),通过主键可以回表到聚簇索引获取完整行。A 是聚簇索引叶子节点的内容;B 中的回滚指针用于 MVCC,不在二级索引中体现;D 的物理磁盘地址 InnoDB 不暴露给存储引擎外部。 |
### 填空题答案
| 题号 | 答案 | 解析 |
|------|------|------|
| F1 | 主键(或"聚簇");数据文件(或"InnoDB 表");1 | 聚簇索引的特点是数据文件和索引文件是同一份,叶子节点存储整行完整数据,每张表只能有一个聚簇索引。 |
| F2 | 递归;高度 | 父节点满了要递归向上分裂,这是 B+树的经典再平衡操作。根节点分裂意味着需要新增一层,树高度 +1。 |
| F3 | 前面;前;2 | 区分度高的列在前可以更早缩小查找范围;等值查询在前避免被范围查询中断最左前缀;`col1 = 'a'` 等值命中,`col2 > 10` 范围命中,但 `col3` 因 `col2` 的范围查询断链而无法使用索引。 |
### 简答题参考答案
**S1 参考答案要点**:
1. **查询 1 索引**:建议建立联合索引 `(user_id, created_at)`。`user_id` 是高区分度的等值过滤列,放前面可以快速定位;`created_at` 放后面可以直接满足 `ORDER BY` 排序需求,避免 filesort。同时 `id` 和 `status` 隐含在主键中,不需要额外覆盖。
2. **查询 2 索引**:建议建立 `(status)` 单列索引。`GROUP BY status` 可以利用索引的顺序分组,减少临时表的使用。虽然 `COUNT(*)` 需要从主键获取,但由于状态数通常很少(如待支付、已发货、已完成等),回表开销很小,不值得为这个查询单独建立覆盖索引。
3. **INSERT/UPDATE 影响**:增加索引会提高写入成本。每个 INSERT 需要在所有索引的 B+树中插入记录,可能导致页分裂。尤其是 `(user_id, created_at)` 联合索引,当 `created_at` 无序时也会触发分裂。可通过预排序批量插入或使用自增 ID + 顺序插入来缓解。
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点(索引设计 × 2 + 原因分析 × 1 + 写入影响 × 1)。
## 关联笔记
- [[02.MySQL/index/B+树索引原理]]