MySQL为什么使用B+树索引
MySQL为什么使用B+树索引
索引
索引的常见类型
- BTREE 索引
- Hash 索引
- FULL-TEXT 全文索引
- RTREE 空间索引
MySQL为什么使用B+树索引
-
二叉树为什么不可行?
对数据的加速检索,首先想到的就是二叉树,二叉树的查找时间复杂度可以达到O(log2(n))。下面看一下二叉树的存储结构
-
平衡二叉树为什么不可行?
为了解决二叉树存在线性链表的问题,会想到用平衡二叉查找树来解决。
平衡二叉查找树定义为:节点的子节点高度差不能超过1,通过左旋、右旋的方式来保证二叉树的平衡。
到这里,平衡二叉树解决了存在线性链表的问题,数据查询的效率也还可以,基本能达到O(log2(n)), 那为什么mysql不选择平衡二叉树作为索引存储结构?
- 搜索效率不足。一般来说,在树结构中,数据所处的深度,决定了搜索时的IO次数(MySql中将每个节点大小设置为一页大小,一次IO读取一页 / 一个节点)。如上图中搜索id = 8的数据,需要进行3次IO。当数据量到达几百万的时候,树的高度就会很恐怖。
- 查询不不稳定。如果查询的数据落在根节点,只需要一次IO,如果是叶子节点或者是支节点,会需要多次IO才可以。
- 存储的数据内容太少。没有很好利用操作系统和磁盘数据交换特性,也没有利用好磁盘IO的预读能力。因为操作系统和磁盘之间一次数据交换是以页为单位的,一页大小为 4K,即每次IO操作系统会将4K数据加载进内存。但是,在二叉树每个节点的结构只保存一个关键字,一个数据区,两个子节点的引用,并不能够填满4K的内容。
-
B树
- B+树
平衡二叉树 & B+树 不同节点量级对应树高比较
数量级(单位/万) | AVL Tree 高度 | BTree 高度(N = 1200) |
---|---|---|
100 | 20 | 2 |
1000 | 24 | 3 |
10,000 | 27 | 3 |
说明:以 InnoDB 的一个整数字段索引为例,这个 N 差不多是 1200。
为什么减少I/O次数?

MySQL InnoDB存储结构
-
表空间
- 默认情况下,只有一个表空间ibdata1,所有数据存放在这个空间内
-
segment 段
- 数据段:B+ tree的叶子节点
- 索引段:B+ tree的非叶子节点
-
extend 区
- 每个区的大小为1M,页大小为16KB,即一个区一共有64个连续的页(区的大小不可调节,页可以)
-
Page 页
- InnoDB磁盘管理的最小单位
-
row 行
- 对应数据表里一条条记录
B+Tree Structure
叶子节点:
非叶子节点:
根节点结构内容:
页中数据存储结构:
联合索引
创建表
构建联合索引,联合索引会将N个字段组合成一个元素,形成一棵B+树,大致如下
查询过程中,会先根据第一列的条件进行查询,查询到满足的值之后,再根据第二列的查询条件继续定位,依次类推。
联合索引的一些特性如下:
-
最左匹配
联合索引的一个特性是最左匹配,也就是当一个查询中,有多个查询条件时候(sql编写顺序无所谓),查询条件需要精确匹配联合索引的左边连续几个列,此时联合索引便可以被用到(用到联合索引的部分列),例如:
age=15 and contry='US' and name='Eric'
:是一个全匹配age=15 and contry='US'
:是一个最左匹配,也能用上联合索引,但是只能用上联合索引的age
和contry
两列age=15
:也是一个最左匹配,也能用上联合索引,但是只能用上联合索引的age
列contry='US' and name='Eric'
:并没有从联合索引的最左列开始匹配,因此无法用上索引age=15 and name='Eric'
:只能用上age
部分的索引,因为缺少了中间字段
最左匹配特性的由来:
我们知道B+树的构造过程中,需要对比插入元素和树中节点的比较结果,来确定元素的插入位置。联合索引生成的B+树中,会优先以第一列的比较结果来定位,第一列值相等的时候,会继续使用第二列的比较结果,依次类推,因此一定要第一列的精确查询条件,才能定位到某些子树,然后才能在子树基础上,继续使用第二列的查询条件,一次类推下去,从而形成一个最左匹配的规则。
-
覆盖索引
在使用非聚集索引查询时,一般会检索两遍数据,不过也会有例外。 当我们要查询的列本身就在索引树中,就不会进行二次查询,也就是覆盖索引。例如
-
范围查询
当联合索引遇到范围查询条件之后,后面的列便无法使用索引,例如:
age>15 and contry='US' and name='Eric'
:能使用age
列的索引,但是无法使用完整的联合索引
在B+树数据结构中进行范围查询,可以先查询到最小/最大值,然后通过叶子节点上的链表指针,按照顺序遍历叶子节点,即可得到范围查询结果,因此当联合索引中的某一列使用了范围查询之后,可以认为是B+树已经深入到最底层的叶子节点做范围查询了,无法再在非叶子节点中根据后续列的查询条件进行检索。
Mysql索引优化建议
- 尽量采用自增ID作主键
- 不要建立太多索引
- 严禁左模糊查询(like '%xxx')
- 利用覆盖索引避免回表
__EOF__

本文链接:https://www.cnblogs.com/GHzcx/p/16385722.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2018-06-17 区块链是什么?