从数据页和B+树的角度看索引失效原因

本文详细解释了InnoDB存储引擎中索引失效的原理,通过数据页结构和B+树的视角分析索引失效场景,包括聚簇索引、二级索引和联合索引的B+树结构,以及索引覆盖和回表的概念。

📚 全文字数 : 6k+

⏳ 阅读时长 : 8min

📢 关键词 : 数据页结构、索引的B+树结构、索引失效原理

场景再现,有多少朋友有过的?

面试官👴:我看你熟悉简历数据库索引,那索引失效有哪些场景?

我👦:巴拉巴拉,把从晚上背的6,7条失效场景一字不落的背出来了

我👦:心里想,这问题能难道我?

面试官👴:能具体一点吗,上一位面试者也是这么说的

我👦:额,心里想,我没背过这个知识点啊,芭比Q了

前言

文章开头的面试场景不是我编出来的,兄弟们,刚毕业一两年面试的我就出现过这种问题。仅仅问你失效场景,只要准备过面试的人都能答出来。但是再往下问问,就不知道怎么答了。

这篇文章将从InnoDB存储引擎的索引B+树和数据页的角度一起来看实际的索引失效问题,设计的内容比较多,关于【数据页】和【索引的知识结构】只是可以翻看我之前的文章有更详细的内容。

大纲

先看大纲,让自己知道今天要讲的内容。

什么是索引失效

我们知道创建索引的目的是为了提高查询速率,但并不是创建了索引就能让查询速率显著提高的。

稍不注意,你是在列上建了索引,可能你写的查询条件也是索引列,但最终执行计划没有走它的索引,从而走了全表扫描,这种建了索引而实际索引没用的情形就是索引失效。

从数据页看B+树

(1)在叶子节点一层,所有记录的主键按照从小到大的顺序排列,并且形成了一个双向链表,便于范围查询。叶子节点的每一个Key指向一条记录。

(2)非叶子节点取的是叶子节点里面Key的最小值。这意味着所有非叶子节点的Key都是冗余的叶子节点。同一层的非叶子节点也互相串联,形成了一个双向链表

在了解索引和索引失效之前,我们应该对数据页,数据页中数据的存储方式,如何构建B+树的这些原理搞清楚!

这些对后续理解为啥使用B+树,B+树的特性会有很大的帮助,而不是为了应付才去死记硬背一些没什么营养的答案。

数据页结构

MySQL读取数据都是以【数据页】为单位读取的,而不是需要读取一条记录的时候就读记录本身,以数据页为读取单位的话,需要将其整体读取内存中,但是各个数据页之间是不连续的。

而数据页默认大小为16KB,意味着每次至少是将16KB的内容疏导内存中。

左侧的是组成数据页的7大部分,右侧是这几部分的简要说明。

不同数据页之间既然不是连续的,那怎么知道这个数据页的下个页在哪?

其实File Header中有两个指针,分别指向上一个数据页和下一个数据页

<think> 我们正在讨论MySQL索引如何从数据结构角度加快查询速度。用户希望从数据结构的角度理解索引加速查询的本质。 根据引用[1],我们知道索引遵循一些基本原则,但用户现在关心的是背后的数据结构原理。 在数据库中,索引是一种数据结构,它允许快速查找访问数据。最常用的索引结构是B(及其变种如B+哈希索引。 1. B/B+索引: - B是一种自平衡的数据结构,它保持数据排序,并允许对数时间复杂度的搜索、顺序访问、插入删除。 - 在数据库中,B+是更常用的索引结构。与B相比,B+的所有数据都存储在叶子节点,内部节点只存储键(用于导航)。叶子节点之间通过指针连接,便于范围查询。 - 通过使用B+索引,数据库可以快速定位到数据所在的位置,而不需要全表扫描。例如,在一个有1亿条记录的表上,全表扫描需要遍历1亿条记录,而使用B+索引,可能只需要3-4次磁盘I/O(因为的高度很低)就能定位到数据。 2. 哈希索引: - 哈希索引基于哈希表实现,它通过将键值映射到哈希表中的位置来快速查找。 - 哈希索引对于等值查询非常快,时间复杂度接近O(1)。但它不支持范围查询(如WHERE a > 10),并且哈希冲突也需要处理。 为什么索引能加快查询? 本质上是减少了需要扫描的数据量(即减少了磁盘I/O操作)。在没有索引的情况下,数据库必须进行全表扫描(顺序访问每一行数据)来找到满足条件的行。而使用索引后,数据库可以利用索引数据结构(如B+)快速定位到数据的位置,然后只读取相关的数据页(通常是磁盘块)。 举例说明: 假设有一个表`users`,其中有一个索引列`age`。当执行查询`SELECT * FROM users WHERE age=25`时: - 如果没有索引:数据库需要逐行扫描整个表,检查每一行的`age`是否为25。 - 如果有B+索引:数据库从索引的根节点开始,根据键值(25)逐层向下查找,最终在叶子节点找到所有age=25的行的位置(通常是行的物理地址),然后根据这些地址去读取对应的行。由于B+的高度通常很低(3-4层),所以只需要几次磁盘I/O操作。 注意:索引虽然能加快查询,但也有代价。它会占用额外的存储空间,并且在数据更新(插入、删除、修改)时需要维护索引,这会导致写操作变慢。 因此,从数据结构的角度看,索引加速查询的本质在于其高效的数据结构(如B+)能够快速定位数据,从而避免了低效的全表扫描。 参考文献: [1] MySQL索引原理及慢查询优化 §§相关问题§§ 1. BB+在索引中的区别是什么? 2. 为什么数据库索引通常使用B+而不是哈希表? 3. 索引的维护成本体现在哪些方面? </think> ### 从数据结构角度分析索引加速查询的本质 索引的本质是一种**高效查找的数据结构**,它通过建立键值与数据位置的映射关系,将随机查询转化为高效的有序查找。核心原理如下: #### 1. **数据结构基础:B+** MySQL索引主要采用**B+**结构(InnoDB引擎),其优势在于: - **多路平衡查找**:每个节点可存储多个键值(如1000+),大幅降低高度(3-4层可存储数十亿数据)[^1] - **有序性存储**:所有键值按顺序存储在叶子节点,满足快速范围查询(`WHERE age>20`) - **物理连续性**:叶子节点通过指针串联,支持高效顺序扫描(避免磁盘随机I/O) 例如查询`WHERE id=100`: ```mermaid graph LR A[根节点<br>50, 150] --> B[子节点1<br>20,40] A --> C[子节点2<br>100,120] C --> D[叶子节点<br>100→磁盘地址0x123] ``` 仅需3次磁盘I/O即可定位数据(实际通过缓存优化更快)。 #### 2. **查询加速原理** | 操作类型 | 无索引 | 有索引 | 加速本质 | |----------------|-------------------|-------------------|--------------------------| | 等值查询 | $O(n)$ 全表扫描 | $O(\log n)$ 搜索| 从线性到对数复杂度 | | 范围查询 | $O(n)$ | $O(\log n + k)$ | 叶子节点顺序访问 | | 排序操作 | 外排序$O(n\log n)$| 索引遍历$O(n)$ | 避免临时排序 | #### 3. **与哈希索引的对比** 哈希索引(如Memory引擎)虽能实现$O(1)$查找: ```python hash_map = {"id_100": "0x123"} ``` 但存在致命缺陷: - ❌ 不支持范围查询(`id>100`失效) - ❌ 哈希冲突需额外处理 - ❌ 无序性导致排序开销大 因此**B+在通用场景更优**。 #### 4. **索引查询的物理过程** 1. 索引根节点常驻内存(Buffer Pool) 2. 二分查找定位子节点路径 3. 叶子节点获取行指针(ROWID) 4. 根据指针回表取数据页 **关键优化**: - 索引覆盖:若所需字段全在索引中,直接返回结果(避免回表) - 最左匹配:复合索引`(a,b,c)`仅支持`a=?`、`a=? AND b=?`等查询 > 索引的本质是通过预排序分层结构,将数据查找的**随机访问转化为顺序访问**,减少磁盘I/O次数。当高为$h$时,查询复杂度仅为$O(h)$而非$O(n)$[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值