(重点)MySQL(入门篇25)MySQL BTree索引背后的数据结构及算法原理

目录

BTree俗称B树,MySQL数据库支持多种索引,但是我们平时主要使用B树索引,所以本文重点介绍B树索引,这是文章目录

一、MySQL数据库索引的原理(数据结构及算法层面)
二、B树(B-treee)和B+树(B + tree) 的区别和联系
二、聚集索引和非聚集索引的区别(结合InnoDB和myISAM)
三、如何正确且高性能地使用索引?

一、数据库索引的原理

1. 索引的本质

数据结构(一种高效获取的数据的数据结构)

2.索引的背景

数据库的主要功能之一i就是数据库查找,如何能查找的更快就是关键,最基本的查找算法就是顺序查找(挨个遍历,等于就取出),但是当数据量十分大的时候比如说10亿,挨个遍历就会变得十分缓慢,这时候产生了许多优秀的算法,二分查找(就像猜数字数据结构要有序)和二叉树查找(数据结构为二叉树),对数据结构由要求,但是很多数据数据不能满足数据结构比如说文章,或者图片,这个时候索引就出现了,索引用某种方式引用(指针指向)数据,,索引这种数据结构适合实现高级的查找算法。(例如3.索引的使用例子)

3.索引的使用例子

在这里插入图片描述
左边是一个表的实例,和地址,右边是**二叉查找数据结构的索引,**时间复杂度O(log2n),十分的快速。

二、 B - tree 和 B + tree的 区别和联系?

  • 大部分数据库都采用 B-tree 或者 B+Tree的数据结构,
  • 为什么应用如此广泛?
  • 效率高,速度快
  • 为什么速度快?
  • 根据磁盘IO读取的原理,和B树的数据结构
  • 为什么不用二叉树呢?
    考虑到磁盘IO的原理,磁盘IO相对于内存是很慢的(移动磁针…)当数据量很大的时候,就不能全部索引都读取到内存上,只能每一个页的加载(对应索引树的节点)为了减少IO的次数**(IO的次数就是B数的高度h)**,h尽量小,所以不用二叉树。

1 B树(Balance-Tree)

1.1 b树的特征
  1. 非叶子节点只能有M个儿子,M > 2
  2. 根节点的儿子数量为 [2,M]
  3. 根节点以外的非叶子节点的儿子数量为[M/2,M]
  4. 非叶子节点的关键字的个数 = 儿子数量 - 1
  5. 所有叶子节点位于同一层
  6. k个关键子,把节点拆分为 k + 1段,指向 K +1个儿子,满足查找树的大小的关系
1.2 特性(注意区分后面的 B + 树)
  • 1.关键字集合分布在整个树上,(B+树在最下端的叶子上
  • 2 一个关键字字出现在一个节点上,(B+树非叶子的节点上的关键字会重复)
  • 3.搜索肯能在非叶子节点,也有肯在叶子节点结束(B+树只能在底部的叶子节点结束)
  • 4.搜索性能等价于在关键字全集内做一个二分查找(B+树…)
1.3 (重点)例子1, 查询元素5

(1)找根节点 9 所在数据读取到内存 然后比较 比较 5 < 9 所以,数据在 B树的左边,下次查询左边

在这里插入图片描述
(2)找到左边 2 6 所在的节点 数据读取到内存,比较 2<5<6 ,所以下一次查找中间的数据
在这里插入图片描述
(3)再次找到中间的数据读取到内存,比较得到答案。5的位置读取 5 指向的地址(指针),就读取到了对应的数据.
在这里插入图片描述

1.4 (重点)例子2, 插入元素 4

(1)和例子1的方式一样连续查找和比较,找到4对应点位置在 3 - 5 之间。
在这里插入图片描述
(2)但是并不能插进入,三阶树的每个节点最多有 (3-1) = 2 个元素,所以只能将 4 上移到 2 和 6 之间。再次判断是否能插入…(上移是关键操作!)
在这里插入图片描述
(3)再次判断,最多只能有 (3-1) = 2 个,单个节点元素过多,再次上移
在这里插入图片描述
(4)此时满足条件,就插入到根节点,此时根节点元素为 4 , 9
在这里插入图片描述
(5)为了满足树的结构,再次对树进行调整,得到最终结果如下。
在这里插入图片描述

1.5 (重点)例子3,删除元素 11

(1)使用例子1的方法查询到 11 的位置删除它
在这里插入图片描述
(2)12 的节点只有一个儿子,不符合树结构了,所以左旋,12下来,13上去 最终结果如图。
在这里插入图片描述
(3)拓展:如果要再删除15呢,元素的个数太少以至于不能再旋转,把12提上去就行了
在这里插入图片描述
在这里插入图片描述

2. B+ 树

在这里插入图片描述

2.1 B+树的特征
  1. B+树是 B树的变体,性能更好,更稳定,MySQL就是B+树
  2. 非叶子节点可以保存 n 个元素B树是n-1个所以上面的的例子只能储存2个)
  3. 所有的元素(节点数字和指向元素指针地址)都能在叶子节点里找到,而且叶子本身就是按照关键字的大小顺序连接
  4. 所有的非叶子节点可以看似索引,元素的[数字值]是儿子节点的最大(或者最小的)[数字值]
  5. 通常 B+树上有 2个头指针,一个指向根节点,一个子项关键字最小的节点,
  6. 所有的元素都能在叶子里找到,上面的节点包含重复的元素。
  7. 根节点的最大的元素就是整个B树的最大的元素
2.2 B+树的查询优势
  1. B+树中间节点不保存数据,所以磁盘也能容纳更多的节点元素显得矮胖
  2. B+树必须查询到叶子才能获得数据,但是并不慢,而且更加稳定
  3. 对于外围查找,B+树只需要遍历叶子节点即可。(数据只存在于叶子节点)

三、为什么使用B树或者 B+树?

数据库的索引本身很大,不能直接全部读取到内存中,只能磁盘分步读取到内存中,因为此磁盘的IO速度十分慢(比内存慢几个数量级),**所以为了尽量减少磁盘的IO,**二叉树,红黑树这种高度很高的数就不适合,就是用B树这种矮胖的结构。

1,主存(内存)存取原理

内存多次读取数据之间的距离不会对速度产生任何影响,举个例子

在这里插入图片描述
(1)读取数据1,就去寻找0x0A地址,读取数据2 找 0x0B
(2)读取数据1,就去寻找0x0A地址,读取数据6找 0x2C地址,
(3)(1)和(2)的耗时是相对的,这就是距离不会对速度产生任何影响

2.磁盘读取数据的原理

索引一般在磁盘上,检索磁盘需要磁盘的IO操作和内存的IO操作有很大的不同,主要是磁盘存在机械运动,耗时十分巨大。

2.1.磁盘读取数据的过程

磁盘读取数据时候,系统会将数据的地址给磁盘,磁盘确定数据的位置,**将磁头移动道对应数据的磁道,(寻道时间)然后旋转到对应的数据的地方(旋转时间)**然后才能读取到对应数据

2.2 局部性原理和磁盘预读

1.预读

(1)预读产生原因:由于储存介质机械运动的 原因,磁盘的读取很慢,比内存差几个数量级,所以要尽力减少此磁盘的IO次数,(减少机械运动的时间)
(2)预读定义:举例如果你只需要一个字节的数据,但是磁盘会直接读取4000个字节(很多操作系统默认4K为1页)到内存,这样做的理论依据是局部性原理
(3)预读的长度为页(page)的整数倍,硬件和操作系统将内存和磁盘分为页(通常为4KB大小)内存和磁盘通过页为数据单位交换数据,当 程序需要的数据不在内存中时候(数据不连续预读失败),会触发一个缺页异常,磁盘会更具缺失的数据的地址重新读取数据和数据后的一页或者几页的数据。因此:尽量保证数据连续,使用预读减少IO
(4)总结:保证数据连续,使用预读减少IO

2.局部性原理

(1)当一个数据被使用的时候,附近的数据很有可能也会被使用,
(2)运行期间需要的数据通常比较集中

四、InnoDB引擎性能优化。

yISAM引擎和InnoDB引擎的区别请看博客(重点)MySQL(入门篇26)聚簇索引和非聚簇索引的区别
在这里插入图片描述

(重点)1.为什么InnoDB所有表建议使用一个自增Id作为主键索引?

1.1节约内存

辅助索引连接的都是主键索引的引用(如图上),如果你用其他过长的索引会让**辅助索引过长内存十分臃肿且浪费**

1.2 (自增id主键)会有连续的索引结构

由上面的内存分析可知道,如果连续的磁盘存储,可以减少读取的IO,mysql会根据主键插入适当的节点和位置,如果达到装载因子(mysql默认15/16)就开辟一个新的页(page)

如果使用自增主键,开辟新的页就是连续开辟,减少IO。(如图)
在这里插入图片描述
所以:
尽量使用一个自增的id作为主键

文章参考
http://blog.codinglabs.org/articles/theory-of-mysql-index.html