数据库索引原理 | 索引数据结构 | B+Tree


文章目录

  • 数据库索引原理 | 索引数据结构 | B+Tree
    • 一. 数据库索引简介
    • 二. 红黑树 与 B-Tree
      • 1. 红黑树
      • 2. B-Tree
    • 三. MySQL 的完美解决方案 —— B+Tree
    • 四. 索引下的 SQL 查询过程
    • 五. MySQL 数据库引擎 MyISAM 与 InnoDB
      • 1. MyISAM 非聚簇索引
      • 2. InnoDB 聚簇索引
    • 其他相关文章

一. 数据库索引简介

索引是帮助 MySQL 高效获取数据的,已排好序的一种数据结构。一般采用的数据结构有:

  • 二叉排序树
  • 红黑树
  • Hash 表
  • B-Tree
  • B+Tree

在通常情况下,若要在 7 条记录中查询某条记录,按顺序表的查询效率较低。例如,查找 7 条记录中的 id 为 5 的值,按顺序查询要查询 5 次。若以二叉排序树来作为索引的数据结构,如下例:

图1. 二叉排序树作为索引数据结构的查询

id 为索引,此时仅需要查找 3 次。可见索引在优化查询方面的巨大价值。

但是以二叉排序树作为检索数据结构在也有诸多缺点。例如:

  • 在插入新值后二叉树需要重新平衡才能保证索引的作用

    二叉排序树若不进行平衡,则不能起到优化查询的目的。若要进行平衡,则会产生格外的性能开销。

    例如,连续插入 id 值递增的数据,二叉树若不平衡,则和链表无异,查询效率也和顺序查询相同。

    图2. 二叉排序树索引的连续递增插入

    提示


    若不清楚为什么新插入的值都链接到右侧,可以去回顾数据结构二叉排序树

  • 不适合做范围查找

    如果在图1. 中情况做范围查询 id 大于 2 的值,查找过程会相对复杂,开销大。

  • 随着数据量的增大,二叉树高度越来越高,查找效率下降

    在第一点中提到必须平衡二叉树后才能起优化查询的作用。假设二叉树每次插入后都进行平衡,当数据量达到上十万时,二叉树的高度也会变得非常大,此时无论是平衡二叉树的操作,还是查找二叉树的操作开销都会非常大。


二. 红黑树 与 B-Tree

在上一节中介绍了索引如何提高查询效率。从中可见,选取合适的数据结构至关重要。我们继续看两种可用的数据结构 —— 红黑树 与 B-Tree。

1. 红黑树

红黑树是一种特殊 AVL 树(平衡二叉树),也称平衡二叉 B 树。其操作的插入与删除都会使得二叉树保持平衡,从而避免图2. 中的情况。

图3. 红黑树索引的连续等增插入

此时相比按顺序查找 5 次找到索引值为 5,红黑树只需要查找 3 次。但是红黑树依然没有解决范围查找与海量数据效率低下的问题。

2. B-Tree

B-Tree 又称多路搜索树,其插入与删除都可以保证平衡,特别的,B-Tree 是 “多叉” 的,而不是二叉的。

为什么想到 B-Tree 树呢?正是因为它是 “多叉” 的。这意味相比二叉树,其一个节点可以链接的节点多于 2(节点的度大于 2),这样节点数相同的情况下,B-Tree 的高度更小,查找的次数也更小。

图4. 高度为 3 的B-Tree(图中的 p 为指向下一节点的指针)

如图4. 所示,这是一颗高度为 3 ,每个节点可以容纳 3 个值的 B-Tree,一共容纳 29 个值。相比高度为 3 的满二叉树只能容纳 7 个值。

此时若假设,数据库表中有 29 条记录,以 id 为索引值分别建二叉树(考虑最理想情况下为平衡二叉树)和 B-Tree 的索引,并查找索引值 28。二叉树的高度为 5,则查找 28 需要进行 5 次查找,而 B-Tree 如图4. 高度为 3,查找 28 仅需要进行 3 次查找。

可见,B-Tree 相对容量大,相对高度增长慢,极大的改善了随着数据量的增大,二叉树高度越来越高,查找效率下降的问题。并且其插入删除也是可保持平衡的。现在唯一的问题就是无法支持范围查询。

提示


  • 为什么有 29 个值节点的平衡二叉树树高度为 5 ?
    平衡二叉树除了最后一层,其他层都是满的,所以最后一层之外的节点总数必为 2 n,n 为除了最后一层外的层数。因此有,24 = 16,25 = 32,24 < 29 < 25,因此 29 个节点构成的平衡二叉树高度大于 4 但不满 5,高度为 5。

    图5. 29个节点的平衡二叉树

  • B-Tree 是如何查找节点 28 的?

  1. 用 28 和根节点(注意,B-Tree 中的树节点容纳了多个值!)中的 12 比较,28 大。28 和 21 比较,28 大,由根节点中的右节点指针查询下一节点。
  2. 在根节点的右节点中,用 28 和 24 比较,28 大。用 28 和 27 比较,28 大,因此根据当前节点的右节点指针继续访问右节点。
  3. 在下一层节点中,找到所查询的值 28,查询完成。

    图6. 29 个节点的 B-Tree


三. MySQL 的完美解决方案 —— B+Tree

B+Tree 是应对数据库表索引的完美数据结构。其在保证 B-Tree 的基础上进行了改造,能够支持范围查询。

图7. B+Tree

如图7. 所示,B+Tree 有以下特征:

  • 节点值冗余,叶节点包含树中所有的值
    我们可以看到根节点中的值 1 和 5 都出现了 3 次;3、5、7都出现了两次。这些冗余值将整个树中各个节点的值 “传导” 到了叶节点上。这使得叶节点中包含了树中所有的值
  • 叶节点包含一个指向同层相邻节点的指针
    我们可以看到叶节点包含了一个指针,指向同层的相邻节点。
  • 叶节点按大小顺序排列
    我们可以发现最后一层的叶节点都是按照大小顺序排列好的。

接下来我们对如图7. 的 B-Tree 树进行查询。

  • B-Tree 查找索引值 4
  1. 从根节点开始,4 和 1 比较,4 大。4 和 5 比较,4 小,由 p1 查询下一节点。
  2. 4 和 3 比较,4 大,由 p4 查询下一节点。
  3. 查询到 4,查询完成。
  • B-Tree 查询大于 4 的所有索引值
  1. 查询索引值 4
  2. 由该索引值所在的叶节点的指针向后查询,得到所有大于 4 的索引值。

至此,B+Tree 解决了在第一节中提出的,二叉树作为索引数据结构的所有问题。


四. 索引下的 SQL 查询过程

接下来我们理解索引情况下具体的 SQL 查询过程。

首先,我们要清楚,数据表文件是存储在磁盘中的,而不是内存中。并且不能说我们直接将磁盘中所有的数据全一次性加载入内存,这样不仅耗费内存而且加载时间很长

而对于索引本身,也是存储在磁盘中的。索引所占的大小也可以很大,不能一次性加载入内存。数据库开始只加载索引的根节点入内存。

假设索引数据结构是 B-Tree(如下图8.),我们来进行一次查询。

图8. B-Tree 索引下的数据表存储

  • 进行查询 select * from index_id = 9
  1. 内存加载根节点。
  2. 由 9 和根节点的 12 比较,9 小。由指针 p1 从磁盘中读取下一节点入内存。
  3. 在下一节点中进行比较。9 和 6 比较,8 大。9 和 9 比较,找到索引值。
  4. 找到对应的索引值,获取其对应的数据表记录磁盘地址,图中为 0x23。
  5. 根据 0x23 磁盘地址找到查询的记录,查询成功。

可见进行了 2 次(不包括根节点加载)磁盘读取就得到了查询的记录。

但是毕竟是 B-Tree,不支持范围查询,所以我们接下来继续看 B+Tree 的查询过程。

图9. B+Tree 索引下的 SQL

  • 进行查询 select * from index_id = 3
  1. 内存加载根节点。
  2. 由 3 和根节点的 1 比较,3 大。由 4 和根节点的 5 比较,3 小。由 p1 指针从磁盘中读取下一节点入内存。
  3. 在下一节点进行比较。3 和 3 比较相等,但是根据 p4 指针继续从磁盘中读取下一节点入内存。
  4. 在下一节点中找到索引值为 3 的节点,并获取其对应的数据表记录磁盘地址,图中为 0x42。
  5. 根据 0x42 读取磁盘中的数据表记录,查询成功。

注意


B+Tree 为索引数据结构的情况下与 B-Tree不同。
B-Tree 中每个节点都保存了对应的磁盘地址,而 B+Tree 中只有叶节点才保存了磁盘地址数据。
所以即便在非叶节点找到了对应的索引值,也必须向下加载节点,直至叶节点,再获取磁盘地址数据。

  • 进行查询 select * from index_id > 4
  1. 和上一点中所描述,查找索引值为 4 的节点。
  2. 由该节点中的 p8 指针向后查找相邻节点,获取索引值 为 5、6 的磁盘地址。再继续由 p9 指针查找下一相邻节点,获取索引值为 7、8 的磁盘地址。
  3. 根据获取的 5、6、7、8 索引值对应的磁盘地址获取磁盘中的数据表记录,查询成功。

可见对于如图9. 中的 B+Tree,1 - 8 索引值的查找全部都需要加载 3 次(不包括根节点加载)磁盘才能完成查询。

那这不是比 B-Tree 查找效率低吗?

实际上不是,图9. 是为了方便描述而设计的 B+Tree,其已经类似于二叉树,因为每个节点的度为 2;并且每个节点也只保存了两个索引值。但实际情况下,我们可以使得每个节点拥有多的分支,保存更多的索引值,如图10. 。此时对于上万条记录的索引存入其中,读取磁盘也仅需 3 次。

图10. B+Tree 索引通常情况


五. MySQL 数据库引擎 MyISAM 与 InnoDB

MySQL 两种常用的数据库引擎 MyISAM 和 InnoDB 都是使用 B+Tree 为索引结构的。但其不同在于,MyISAM 是非聚簇索引,而 InnoDB 是聚簇索引

我们从 MyISAM 引擎的数据表文件与 InnoDB 引擎的数据表文件进行比较。

图11. MyISAM 引擎的数据表文件与 InnoDB 引擎的数据表文件

MyISAM 的数据表有三个文件,后缀分别为 .frm.MYD.MYI。而 InnoDB 的数据表有两个文件,后缀分别为 .frm.ibd。这里 .frm 文件不做讨论。

1. MyISAM 非聚簇索引

在本文中,图1. 、图8. 、图9. 展示的都是非聚簇索引的情况。以图9. 为例。

图12. MyISAM 文件情况

在 MYI 文件中,存储的其实就是索引结构 B+Tree,而数据表数据则都存储在 MYD 文件中。

所以在 MyISAM 的数据表进行检索查询时,先得到 MYI 文件中查,再到 MYD 中拿。这就是非聚簇索引。

2. InnoDB 聚簇索引

InnoDB 的数据表文件除了 .frm 只有一个 .ibd 文件。这个文件相当于将 MyISAM 的两个文件结合了。如图13. 在索引值下,直接接上了数据表的记录。

图13. InnoDB 文件情况

这样的情况下,相比 MyISAM 两个文件分开,要先查再拿。InnoDB 聚簇索引在查找到之后就可以直接拿到数据记录,效率更高。

MyISAM 与 InnoDB 的其他不同


  • MyISAM 在 MySQL 5.5 之前是默认数据库引擎,之后 InnoDB 为默认的数据库引擎
  • MyISAM 可以不设立主键,InnoDB 必须建立主键。
  • MyISAM 不支持事务,InnoDB 支持事务。
  • MyISAM必须依靠操作系统来管理读取与写入的缓存,而InnoDB则是有自己的读写缓存管理机制。
  • InnoDB 支持外键,而 MyISAM 不支持。

MyISAM 和 InnoDB 的区别还有很多,这里只列举部分,读者可以多查找资料。


其他相关文章

文章名称 更新时间
数据库索引原理与索引数据结构 2021-05-23
数据库索引优化 准备中

文章内容来自个人学习总结 欢迎指出本文中存在的问题 未经本人同意禁止转载,不得用于商业用途

【MySQL】数据库索引原理 | 索引数据结构 | B+Tree相关推荐

  1. Mysql数据库管理系统原理及基本操作

    文章目录 Mysql数据库管理系统原理 一.引子: 二.数据库种类: 三.数据库解决的问题: 四.数据库的作用: 五.SQL结构语句: 六.关系型数据库结构: 七.存储引擎: 八.数据库存储和查询: ...

  2. Mysql数据库主从原理

    一.什么是数据库主从 主从复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数据库.从数据库存储的数据和主数据是完全一模一样的. 二.主从复制的原理 Mysql数据库主从原理大致有三个步骤: ...

  3. MySQL数据库篇之索引原理与慢查询优化之一

    主要内容: 一.索引的介绍 二.索引的原理 三.索引的数据结构 四.聚集索引与辅助索引 五.MySQL索引管理 六.测试索引 七.正确使用索引 八.联合索引与覆盖索引 九.查询优化神器--explai ...

  4. B+树:MySQL数据库中建立索引的数据结构

    在MySQL数据库中是通过B+树的数据结构建立索引的. 相比二叉树,B树是一种多叉树,总层数更少,磁盘io次数也会相应减少.而与B树不同的是,B+树把索引和数据分开存储,数据以链表的形式存放在B+树的 ...

  5. mysql数据库如何创建索引,删除索引

    写在前面:要想了解索引的底层以及优化索引的底层还得学习不同搜索引擎下对于数据的处理,后续我会出一些相关的文章介绍,比如什么是B+tree,什么是聚簇索引什么是二级索引.联合索引等,以及不同搜索引擎下( ...

  6. 【学习笔记】MySQL数据库高级版 - 索引优化、慢查询、锁机制等

    本文是尚硅谷周阳(阳哥)老师的MySQL高级篇视频的学习笔记.由于视频比较老,所以在高版本的MySQL中索引的地方做了优化,和视频的内容不完全一样,不过大体一致.从第四节锁机制开始的部分还没有整理. ...

  7. MySQL数据库中的索引(含SQL语句)

    文章目录 为什么要用索引 索引是什么 索引的原理 优点 缺点 创建索引的原则 什么情况下需要索引 什么情况下不需要索引 索引的分类 主键索引 单值索引 唯一索引 组合索引(复合索引) 全文索引(仅在M ...

  8. MySQL数据库——事务和索引

    目录 一.事务: 事务四大特性: 并发事务带来哪些问题?(隔离所导致的一些问题) 事务隔离级别有哪些? MySQL的默认隔离级别: 二.索引: 索引的作用: 索引的分类: 索引准则: 索引的数据结构: ...

  9. mysql数据库学习之索引

    数据库为什么要使用索引? 首先说下全表扫描,存储的最小单位是块或页,整个表就是多个块或页,我要进行查找操作就必须将所有的块或页加载进内存,然后一个一个的去查找,这样效率低下.所以我们引入索引. 举个例 ...

最新文章

  1. 使用模板元编程快速的得到斐波那契数。。
  2. Mysql之case when用法总结
  3. JVM PermGen –您在哪里?
  4. 数据结构与算法简单总结()
  5. mysql命令行的几个用法
  6. [EOJ]2019 ECNU XCPC March Selection #1 F
  7. android测距传感器,测距测量仪(专业测量软件)
  8. 菜单栏底部线条切换效果
  9. python tab键自动补全_设置python中TAB键自动补全方法
  10. Asp.Net IIS 管理类(全)
  11. IIS7.5标识介绍
  12. 点击类名方法名如何连接到相应的Android源代码
  13. JavaEE(26) - {TODO}
  14. no target device found怎么解决_关于移动端开发 1px 线的一些理解和解决办法
  15. 榛子云——短信(工具)
  16. 第一周学习报告(关于string)
  17. C++类内初始值的初始化形式
  18. K--最邻近(K-NN)算法
  19. java中控制反转_Java如何利用IOC控制反转的三种设计模式详解
  20. 〖金融帝国实验室〗(Capitalism Lab)深度研究文章——《浅析210年周期的城市宏观经济》(作者:jiuliumuliao)

热门文章

  1. matlab 比较两个结构体,用于比较 MATLAB 结构体数组的比较器 - MATLAB - MathWorks 中国...
  2. 相似图片搜索的原理(二)
  3. 什么是有机硅胶 有机硅胶具有哪些显著特性
  4. Ubuntu系统忘记密码怎么办(进阶处理)
  5. 糖化学试剂2199491-27-3,L-Glutamamide,激肽释放酶抑制剂肽,信息说明
  6. Android画笔Paint与文字相关的设置
  7. 使用递归方法进行逆序输出字符串
  8. 常见函数及其图像-----专升本
  9. 数据卷mysql挂载
  10. 一、SpringCloud 微服务架构