Administrator
发布于 2026-01-13 / 2 阅读
0

面鸭突击30之Day2

Q1:为什么 MySQL 选择使用 B+ 树作为索引结构?

一、 常见数据底层索引结构对比

1. 二叉树类索引(红黑树、AVL 树)

  • 共性:均为自平衡二叉搜索树,查询、插入、删除的时间复杂度均为 O(log**n);

  • 核心差异

    • AVL 树:严格高度平衡,任意节点的左右子树高度差绝对值 ≤ 1,树高更接近理想值 log2n

    • 红黑树:近似平衡,通过节点着色规则保证黑高度平衡,树高最大为 2log2(n+1),树高:红黑树 > AVL 树

  • 磁盘存储下的致命缺陷

    二叉树的每一层节点对应一次磁盘 IO 操作,执行单条查询时最坏情况需遍历「根节点→叶子节点」的所有层级,树高越高则 IO 次数越多,

    磁盘 IO 开销巨大;

  • 适用场景:仅适合内存数据的索引(如 JDK TreeMapConcurrentHashMap),不适合磁盘存储的数据库索引。

2. Hash 索引

  • 核心优势:基于哈希表实现,等值查询时可通过哈希函数快速定位数据,时间复杂度接近 O(1);

  • 核心缺陷

    1. 存在哈希冲突问题(需通过链表 / 红黑树解决冲突,增加额外开销);

    2. 不支持范围查询和排序:哈希函数会打乱数据的有序性,无法高效完成 ><BETWEEN 等范围操作;

    3. 等值查询性能优异,但无法利用索引完成部分查询优化(如覆盖索引);

  • 适用场景:仅适合等值查询为主的场景(如 Redis 的哈希表),无法满足数据库的复杂查询需求。

3. B 树

  • 结构特点:多路平衡搜索树,非叶子节点和叶子节点均存储数据

  • 与 B+ 树的核心区别

    对比维度

    B 树

    B+ 树

    数据存储位置

    非叶子节点 + 叶子节点

    仅叶子节点存储数据

    叶子节点关联

    无关联

    叶子节点通过双向链表链接

    范围查询效率

    低(需回溯上层节点)

    高(直接遍历叶子节点链表)

    非叶子节点作用

    存储数据 + 索引导航

    仅做索引导航

二、 数据库为何选择 B+ 树作为主流索引结构

B+ 树的优势完美适配磁盘存储的数据库场景,核心优势如下:

  1. 查询性能稳定,IO 开销低B+ 树的非叶子节点仅存储索引键值和子节点指针,不存储数据,因此单个非叶子节点能容纳更多索引条目,树的高度更低(通常 3~4 层即可支撑千万级数据)。无论查询哪个数据,最多只需 3~4 次磁盘 IO,相比二叉树类结构的 IO 次数大幅减少,查询性能稳定。

  2. 天然支持范围查询和排序B+ 树的叶子节点通过双向链表有序链接,执行范围查询时,只需定位到范围的起始叶子节点,然后沿链表遍历即可,无需回溯上层节点,效率远高于 B 树和二叉树。

  3. 更适合磁盘预读机制磁盘 IO 具有「预读特性」—— 读取数据时会一次性加载相邻的磁盘块到内存。B+ 树的叶子节点按顺序存储,且链表链接,预读机制能大幅提升范围查询的效率;同时非叶子节点的紧凑结构也能减少 IO 次数。

  4. 便于实现覆盖索引覆盖索引是指查询的字段全部包含在索引中,无需回表查询。B+ 树的叶子节点存储完整数据(InnoDB 中存储整行数据或主键值),可直接通过索引完成查询,避免回表的额外开销。

三、 面试追问

1. 3 层 B+ 树能存储多少数据?

image-20260113下午40820781.png

前提条件

  • InnoDB 默认页大小:16KB;

  • 索引键类型:BIGINT(8 字节);

  • 页指针大小:6 字节;

  • 叶子节点单条数据行大小:1KB。

计算过程

  • 根节点(非叶子节点):仅存储「索引键 + 页指针」,单个条目大小 = 8 + 6 = 14 字节;

    单页可存储条目数 =16∗1024/14≈1170个,即根节点可指向 1170 个二级节点。

  • 二级节点(非叶子节点):结构与根节点一致,每个二级节点也可存储 1170 个条目;

    二级节点总条目数 = 1170∗1170=1368900个,即指向 1368900 个叶子节点。

  • 叶子节点:存储「索引键 + 数据行」,单页可存储数据行数 = 16∗1024/1024=16 条。

  • 3 层 B+ 树总存储数据量 = 1368900∗16=21902400 条(约 2200 万条)。

补充:实际场景中,数据行大小、索引键长度、页内开销(如页头信息)会影响最终存储量,但 3 层 B+ 树支撑千万级数据是行业共识。

2. 为什么 InnoDB 要求主键尽量短?

InnoDB 采用聚簇索引架构,主键的长度直接影响索引的空间效率和查询性能,核心原因如下:

  • 影响主键索引的非叶子节点效率:主键索引的非叶子节点存储「主键值 + 页指针」,主键越短,单个非叶子节点能容纳的条目数越多,树高越低,IO 次数越少;

  • 影响二级索引的空间占用:二级索引的叶子节点存储「二级索引键 + 主键值」,主键越短,二级索引的单个条目体积越小,占用的磁盘空间越少,查询时加载的索引数据也越少。

结论:短主键能降低索引的空间开销,提升索引的查询效率,因此 InnoDB 建议使用自增 INT/BIGINT 作为主键,避免使用长字符串主键。

3. MongoDB 早期用 B 树,后期为何换成 B+ 树?

  • 早期选择 B 树的原因:MongoDB 早期定位为「文档型 NoSQL 数据库」,以单文档的等值查询为主,B 树的非叶子节点存储数据,等值查询时可能无需遍历到叶子节点,能减少一次 IO;

  • 后期换成 B+ 树的核心原因:随着业务发展,范围查询需求大幅增加。B+ 树的叶子节点双向链表天然支持高效范围查询,且排序性能更优;同时 B+ 树的查询性能更稳定,更适合大规模数据的场景。

Q2:MySQL 索引的最左前缀匹配原则是什么?

最左匹配原则是使用联合索引的时候,查询条件会从最左侧的索引开始匹配,然后再是第二列,当第二列没有的时,但是有第三列的时候,若开启了索引下推,则会在引擎层进行条件过滤,减少回表的次数。

索引下推的条件:查询条件需要查询覆盖索引之外的列、索引失效场景(前%查询、函数转换、字符集不匹配等) 索引下推的主要目的是检查回表次数(大量减少io,直接在引擎层使用联合索引的索引当过滤条件)

联合索引(a,b,c),则生成的联合索引树就是先按a排序,a等再按b排,b等再按c排 mysql8.0.13对于联合索引做了优化:skipscan,对于左边的值的数量不多的情况下,当查询没有使用到左边的索引值,只使用右边值的时候,mysql会将查询sql优化成多条等值的sql查询,来使sql走索引查询,extra也就是Using index for skip scan。执行计划也就会将查询的type 变成走range。 skip scan的局限点: 需要使用联合索引,查询不能跨表、查询不能使用group by 和 distinct、查询只能使用一个索引且不能回表、查询条件需要是常量

其实当查询结果被联合索引覆盖的时候,不符合联合索引的查询也会走联合索引,mysql更倾向于扫二级索引拿值,但是这个就不知道是怎么弄的了

拓展:

1.为什么>=不会停止匹配,但是>会停止匹配,因为>=有明确的边界,在条件a=的条件下,后面的bc是有序的,可以进行比较,但是>的情况下,还是通过遍历过滤的 2.在查询条件内a,b联合索引。a =1 and b=1 和 b=1 and a =1 对于优化器来说是一样的 3.索引失效的场景: 1.前模糊查询,破坏了最左前缀,中模糊查询,破坏了连续 2.函数运算/数值运算,String 比较 没有''的字段 3.字符集转换 4.or查询的查询条件没有索引 5.使用select* 6.not exists 7.order by 的字段需要最左匹配,需要添加limit 和where

Q3:MySQL 三层 B+ 树能存多少数据?

前提条件

  • InnoDB 默认页大小:16KB;

  • 索引键类型:BIGINT(8 字节);

  • 页指针大小:6 字节;

  • 叶子节点单条数据行大小:1KB。

计算过程

  • 根节点(非叶子节点):仅存储「索引键 + 页指针」,单个条目大小 = 8 + 6 = 14 字节;

    单页可存储条目数 =16∗1024/14≈1170个,即根节点可指向 1170 个二级节点。

  • 二级节点(非叶子节点):结构与根节点一致,每个二级节点也可存储 1170 个条目;

    二级节点总条目数 = 1170∗1170=1368900个,即指向 1368900 个叶子节点。

  • 叶子节点:存储「索引键 + 数据行」,单页可存储数据行数 = 16∗1024/1024=16 条。

  • 3 层 B+ 树总存储数据量 = 1368900∗16=21902400 条(约 2200 万条)。

补充:实际场景中,数据行大小、索引键长度、页内开销(如页头信息)会影响最终存储量,但 3 层 B+ 树支撑千万级数据是行业共识。 innodb_page_size可以调整页面的大小,4kb 8kb 16kb 32kb 64kb,页越大,扇出越大,树越矮。但是页越大的缺点就是:内存利用率不够空间浪费,恢复慢,查询定位慢、不可动态修改,初始化好后修改得重新建表