文章目录

  • 一、B-树索引
    • 1. 理论部分
    • 2. B树
      • 黄色的data表示key索引所在的这一行的数据,data存储的是数据本身内容,还是数据在磁盘上的地址?
      • 关于操作系统从磁盘读取索引文件到内存中的几个问题
      • B树的缺点
  • 三、B+树
    • B+树特点
    • MySQL最终为什么要采用B+树存储索引结构?

一、B-树索引

1. 理论部分

数据库索引是存储在磁盘上的,当数据量大时,就不能把整个索引全部加载到内存了,只能逐一加载每一个磁盘块(对应索引树的节点),索引树越低,越矮胖,磁盘IO次数就少

MySQL支持两种索引,一种的B-树索引,一种是哈希索引,B-树和哈希表在数据查询时的效率是非常高的。这里我们主要讨论一下MySQL InnoDB存储引擎,基于B-树(但实际上MySQL采用的是B+树结构)的索引结构。

B-树是一种m阶平衡树,叶子节点都在同一层,由于每一个节点存储的数据量比较大,所以整个B-树的层数是非常低的,基本上不超过三层。

由于磁盘的读取也是按block块操作的(内存是按page页面操作的,一般是16k,是内存页面的整数倍,读1块,刚好放到4个内存页面上),因此B-树的节点大小一般设置为和磁盘块大小一致,这样一个B-树节点,就可以通过一次磁盘I/O把一个磁盘块的数据全部存储下来,所以当使用B-树存储索引的时候,磁盘I/O的操作次数是最少的(MySQL的读写瓶颈,主要集中在磁盘I/O上

数据和索引都是放在磁盘上的,MySQL server得通过操作系统把磁盘上的数据加载到内存中。也就是说,运行起来的进程要访问索引,需要花费磁盘I/O,先把数据、索引读到内存中,而磁盘I/O很影响效率。

在C/C++中,如果我们new/malloc向内存申请4个字节,实际上不可能只拿4个字节,内存管理是按页面4K为大小单位的,操作系统相当于批发站,它批发内存是以页面为单位的,我们申请4个字节,实际上我们向内核kernel申请,内核是按页面给我们分配的。按页面分配以后,但是我们的应用程序只需要4个字节,还剩下的字节就被C函数库libc.so或者 libc++.so库的ptmalloc(缓存)tcmalloc来管理,相当于2个函数,负责管理剩下的空闲的字节,等你下次还malloc申请字节的时候,CPU就不用通过中断切换到内核态,直接在用户空间,从C库分配出来就可以了。等用光了,才向内核申请。

假设用AVL树存储20000000条数据,需要25层

在最坏的情况下,所有的数据都不在一个磁盘块上,读取所有的数据到索引树上,OS需要读取25次磁盘块。我们利用索引读取一条数据,最多需要查找25次

2. B树

涉及到磁盘到内存的一些读取,我们一般都采用B树结构。B树是平衡树,所有叶子节点都同在一层,B树是m阶平衡树(就是多叉AVL树),一般取值300-500。用B树来存储2千万的索引,假如m取500:


最多3层,最多3次磁盘I/O就可以了

在真实项目中,由于数据库表的数据数量会有所控制,构建的B+树也都不会超过3层,B树则可能会有4-5层

我们在student表中把uid设置为主键,会自动创建索引,当我们进行查询查询操作的时候

select * from student where uid=3;

使用索引查找过程:MySQL应用程序一看过滤条件的属性有索引,则先请求存储引擎,然后请求kernel,从磁盘上读uid的索引文件到内存上,然后拿读取的索引的数据构建B树来加速搜索

黄色的data表示key索引所在的这一行的数据,data存储的是数据本身内容,还是数据在磁盘上的地址?

  • 对于MyISAM而言,*.MYD*.MYI分别存储数据和索引,即数据和索引分开存放,所以在索引树上存放的只有实际数据在磁盘上的地址,而没有数据本身。

  • 对于InnoDB而言,*.idb存放的是数据和索引,数据和索引一起存放, 所以索引树上存放的就是数据本身。这就解释了为什么我们create table的时候不设置主键,InnoDB会自动生成主键,就是因为不建立索引就没有索引树,数据就没有地方存放。

关于操作系统从磁盘读取索引文件到内存中的几个问题

  1. 索引文件在磁盘上存储,磁盘的索引文件中的索引就是已经按B+树构建好的吗?

    答:那肯定不是,磁盘上只是存储的二进制文件,读取索引文件的时候,在内存上构建一颗B+树存放磁盘上读来的索引数据。数据结构都是在内存上表示的,没有说磁盘上构建个数据结构。

  2. 操作系统把磁盘的索引文件读到内存上构建B+树,如果磁盘的索引文件太大,内存读不下怎么办?那磁盘IO怎么算次数,现在不是都在内存上的B+树搜索读取数据了吗?

    答:先读索引文件的前几个字节,里面有第一个要读取的根节点数据在索引文件中的偏移量,读取根节点后,根据你要搜索的数据进行搜索,看是接着加载他的哪个孩子节点。 包括根节点的每一个节点,都存储了索引key值和它的孩子节点在磁盘上的位置偏移量信息。
    这样每一次搜索,最多只从根节点沿着某个路径加载到叶子节点上,而不可能是整个索引文件都加载到内存

  3. 在B树和AVL树上搜索一个数据都是O(log2N),为什么还要使用B树?

    答:我们读取数据总共分为两步:花费磁盘I/O把数据从硬盘读到内存,在内存上构建B树,然后到B树上搜索。虽然在内存上搜索的时间都是O(log2N),但B树高度更低,花费的磁盘I/O更少,速度更快

问题总结:索引文件在磁盘上是二进制的,但是文件中存储了根节点的key值和这个节点的整个的偏移量,还存储的它的左右孩子的key值和整个节点的偏移量。操作系统从磁盘的索引文件中,一次读取一个block块的大小(最好是一个节点大小)到内存中构建B+树,然后在节点中二分搜索元素,如果发现值大于根节点的所有数据值,那么就继续从磁盘的索引文件中把该节点的右孩子节点加载到内存上,然后进行二分搜索查找,以此类推下去。

举个搜索的例子

select * from student where name = "zhangsan";

如果name没有索引,在MyISAM中(索引和数据分开存放),就是把整张表过1遍,效率非常低。加个limit 1,就是找到第一个符合条件的数据,就会停止查找,效率提高一些

如果我们给name建索引,当我们再去执行这个select语句的时候,MySQL server就知道name有索引,直接加载name的索引文件,花费磁盘I/O,把磁盘上的索引(name)加载到内存中来,以二分查找的方式(会比较索引的大小关系)构建成B-树。

B树的缺点

每个节点中有key(索引),也有data(对于MyISAM来说是数据的地址,对于InnoDB来说是数据本身),但是每一个节点的存储空间是有限的,data占用较大时,会导致每个节点存储的key就会减少(即树的分支变少),同样会导致B树的高度较大,磁盘IO次数花费增大,效率降低!!!

三、B+树

B+树特点

  1. 非叶子节点相当于是叶子节点的索引,不存储数据,叶子节点用于存储关键字以及数据。 即每个B+树非叶子节点相对于B树的叶子节点能存储更多的key,这样树的高度就更低,花费的磁盘I/O就更少,查找更快。
  2. 由于数据全部存在于叶子节点,所以无论查找哪个数据,花费的磁盘I/O次数都是一样的,查找数据耗费的时间比较稳定
  3. 叶子节点被串在链表中,形成了一个有序链表。做范围搜索和整表遍历的时候直接遍历这个有序链表即可,不用遍历平衡树

MySQL最终为什么要采用B+树存储索引结构?

  1. 在B树中搜索时,离根节点近的节点找的就快,离根节点远的节点找的就慢,查找数据花费的时间不稳定。B+树所有的数据都在叶子节点,查找数据花费的时间稳定
  2. B树的每一个内部节点,都存了key和对应的数据。而B+树的非叶子节点只存关键字,不存数据,B+树的叶子节点存放key和数据。节点的大小是一个块的大小,在节点大小相同的情况下,由于B+树的非叶子节点不存储数据,存储的关键字(key)会远远多于B树,因此,B+树的高度要小于B树,使用的磁盘I/O次数少,查询更快。
  3. 节点内存在的索引值越多,相邻索引值之间的区间就会越小,查找范围越小,查找的就越容易。而B树非叶子节点相邻索引值之间的区间比B+树要大
  4. B树不方便做范围搜索(where age between 10 and 20),整表遍历也不方便。而B+树将所有的叶子节点都串在链表上,做区间搜索以及整表遍历比平衡树快

当我们回答问题的时候,不要1 2 3这样把答案背出来,这样效果是很差的,我们回答索引的底层原理的时候可以这样回答:

当我们select * from student where name="zhangsan"的时候,数据库引擎会检查name字段有没有索引

若没有索引数据库引擎会做整表搜索,效率是比较低的。

如果有索引,数据库引擎会向内核申请从磁盘上读取索引文件到内存,一个节点一个节点在内存上构建B+树,一个节点对应一次磁盘I/O。非叶子节点只存关键字key,所有的key和data都会出现在叶子节点,所以用B+树构建索引树,会以最少的磁盘I/O构建出来。其次搜索的时候是以二分的方式进行搜索的,O(log2N)的效率还是很高的。甚至还可以解释一下为什么使用B+树而不使用B树。

MySQL索引底层实现原理(B树和B+树)相关推荐

  1. MySQL索引底层实现原理 MyISAM非聚簇索引 vs. InnoDB聚簇索引

    MySQL索引底层实现原理 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构. 我们知道,数据库查询是数据库的 ...

  2. 面试官:MySQL索引底层数据结构原理与性能调优,你能回答多少?

    哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新,可以微信搜索[小奇JAVA面试]第一时间阅 ...

  3. 3层b+树索引访问磁盘次数_深入理解MySQL索引底层实现原理丨技术干货

    一.索引的本质 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构. 我们知道,数据库查询是数据库的最主要功能之 ...

  4. MySQL索引底层数据结构原理剖析

    一. 前言 1. 说明 我们平时所说的:聚集索引(主键索引),次要索引,覆盖索引,复合索引,前缀索引,唯一索引在MySQL5.7和 8.0版本默认都是使用B+Tree索引,除此之外还有 Hash索引. ...

  5. mysql索引底层实现原理_mysql的索引底层之实现原理

    MySQL索引背后的数据结构及算法原理 一.定义 索引定义:索引(Index)是帮助MySQL高效获取数据的数据结构. 本质:索引是数据结构. 二.B-Tree m阶B-Tree满足以下条件: 1.每 ...

  6. MySQL索引底层实现原理

    索引的本质 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构. 我们知道,数据库查询是数据库的最主要功能之一. ...

  7. 深入理解 MySQL 索引底层原理

    hi ,大家好,今天分享MySQL硬核知识,希望大家可以学习到真正的知识,慢慢积累,厚积薄发: 看完本文可以学到什么  一步一步推导出 Mysql 索引的底层数据结构  怎么分析回答技术选型问题 一步 ...

  8. Mysql 索引底层原理

    一步一步推导出 Mysql 索引的底层数据结构. Mysql 作为互联网中非常热门的数据库,其底层的存储引擎和数据检索引擎的设计非常重要,尤其是 Mysql 数据的存储形式以及索引的设计,决定了 My ...

  9. MYSQL索引底层原理

    MYSQL索引底层原理 1. 索引的本质 索引是帮助MYSQL高效获取数据的排好序的数据结构. 索引一般以文件形式存储在磁盘上. 2. 按索引的分类 2.1. 按字段约束分类 2.1.1. 普通索引 ...

最新文章

  1. python实训收获_英泰移动通信:学习Python心得体会
  2. 15:18 2009-7-5 小结
  3. obfuscator-llvm Theos 集成配置
  4. [vue] watch和计算属性有什么区别?
  5. SELECT TOP n 性能测试
  6. MegaRAID Storage Manager RAID管理工具实用教程
  7. Python画一个国旗
  8. 广数系统加工中心编程_编程十五年,谈谈对加工中心编程的一些看法...
  9. Unity 安装个人免费版
  10. 使用Visual Studio命令提示查看cad中的重整函数
  11. python将xls格式转成xlsx格式
  12. C语言:二进制转换十进制
  13. it行业se是_CS、IT、SE到底有什么区别?
  14. 网易云信服务监控平台实践
  15. Angular学习笔记——自定义指令directive参数详解
  16. Hbase2.4.1集群安装:HMaster自动挂掉问题终于解决了
  17. 深入浅出内存马(一)
  18. 统计一个字符串中大写字母,小写字母,以及数字的个数。
  19. [乡土民间故事_徐苟三传奇]第九回_小机灵撒谎没功夫
  20. 小熊维尼项目冲刺 第二天

热门文章

  1. python进程池如何复用_python进程池剖析(一)
  2. 侯捷C++->虚函数与多态
  3. python实现电子相册_qt电子相册
  4. extract()函数
  5. DirectX11 几何体示例Demo
  6. Redis-replicator作者陈宝仪:详解Redis协议
  7. 正则表达式高阶技巧之环视(使用python实现)
  8. 正则表达式 第二篇:环视
  9. 我与机器斗争过但失败了:与深蓝“人机大战”20年,卡斯帕罗夫TED演讲
  10. 大头贴计算机教程,如何用电脑摄像头做大头贴