MySql进阶索引篇01——深度讲解索引的数据结构:B+树(三)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 深度讲解索引的数据结构:B+树

5.索引的代价

索引的代价主要是空间与时间代价。


空间上:创建索引需要存储空间。一个数据页的存储空间是16kb,如果一棵B+树有很多数据页,将会消耗较大的存储空间。

时间上:进行数据的增删改操作,同时需要对索引进行维护。主要是页面移动、页面回收、页分裂等代价。

后面的博客中,我们也将一起学习在哪些字段上适合创建索引。

6.B+树与常见的查找数据结构对比

Mysql索引的作用就是减少I/O次数,从而实现数据查找速度的提升。因此我们将以这个作为目标深入对比Hash索引,ALV树,B树和B+树,从而剖析为什么要选择B+树作为Mysql的索引底层数据结构。


6.1 Hash结构

一般提到要加快查找的速度,我们都会考虑两种数据结构:树和哈希。哈希算法的查找效率很高,可以很快的定位到数据的具体位置,通常1次检索,时间复杂度平均为

O(log2n)

而B+树还需要多次I/O,时间复杂度为O(n)


HashMap就是典型的Hash算法应用实例,下图展示了HashMap的数据结构。

哈希算法可以通过计算使一个key对应唯一value。这样我们就可以通过哈希算法计算数据应该存储的地址,把一个数据映射到一个地址。

但有时候,可能会出现两个key计算得到的地址相同的情况,我们称之为碰撞。这时我们

可以通过链接法解决。

如下Demo01是采用普通算法进行搜索,输出时间是1604ms.

public class Demo01 {
    public static void main(String[] args) {
        int [] arr = new int [100000];
       for (int i = 0; i < 100000; i++) {
            arr[i] = i ;
        }
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) { // search 10000 times
            int temp = i;
            for (int j = 0; j < arr.length; j++) {
                if(temp ==  arr[j]) {
                    break;
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("cost " +(end - start) + " ms.");
    }
}

下面算法则花费时间9ms,显然hash算法的查找效率比全表扫描快很多

public class Demo02 {
    public static void main(String[] args) {
        HashSet set = new HashSet(100000);
        int [] arr = new int [100000];
        for (int i = 0; i < 100000; i++) {
            set.add(i);
        }
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) { // search 10000 times
            int temp = i;
            set.contains(temp);
        }
        long end = System.currentTimeMillis();
        System.out.println("cost " +(end - start) + " ms.");
    }
}

既然hash算法的查询效率这么高,为什么InnoDB、MyISam的索引结构要设计成为树型解构呢?


hash算法主要适用于等值判断(==,In查询),对于范围查询,还是只能通过全表扫描来完成,时间复杂度将会退化为O(n).

Hash算法存储元素是无序的,如果需要进行OrderBy等操作无法完成。

Hash算法不适合进行联合索引的查询。

当索引列重复元素较多时(比如性别),会造成大量的哈希冲突,解决哈希冲突将导致效率较低,查找效率也会变低。

总结来说,索引操作并不是只进行等值判断,或者重复元素较多的列,不适合使用hash索引。

索引引擎对于hash索引的支持情况如下图。

hash结构的索引适用于key-value型的数据库,Redis是现在很火的非关系型数据库,它的底层核心就是hash索引。Mysql中如果需要频繁的对索引进行等值判断,可以考虑使用Memory引擎。


另外,InnoDB虽然不支持Hash结构的索引,但是它提供了自适应哈希索引(Adapter Hash Index).如果某个数据页经常被访问,其地址就会被存储到哈希表中,这样下次访问时就可以直接找到这个页面的位置,这也使B+树具备了hash索引的优点。其过程可以参考下图理解。

可以通过如下命令查看数据库中是否开启了自适应hash索引。

6.2 二叉搜索树

二叉搜索树具有如下特点:

  • 一个节点最多有两个子节点,也就是节点的度不能超过2
  • 每个节点左子结点<本节点<右子节点。

其结构可以参考下图。

二叉搜索树的查找很简单,从根节点开始查找,如果查找元素比当前节点小,则在左子树中查找,如果查找元素比当前节点大,则去右子树中找。如果相等,则返回当前节点。二分查找就是利用二叉搜索树实现的。其平均时间复杂度也是O(log2n)

但是二叉搜索树的最大时间复杂度也是O(n)

因为当数据是有序时,构建的二叉搜索树会退化为线型结构哦。

为了避免出现上面的情况,我们需要对二叉搜索树的深度进行限制,AVL树就做到了这一点。

6.3 AVL树

AVL树即平衡二叉搜索树。AVL树可以是空树,除了这种特殊情况外,它要求:

  • 左、右子树的高度差不能超过1
  • 左、右子树也都是一棵平衡二叉树

上面的平衡二叉树查找一个元素最多需要五次I/O操作,有没有办法让其查找效率更高呢?

我们可以把二叉树变成m叉树,比如同样多数量的节点,在下图的三叉树中只需要四次I/O操作就可以查找到一个元素了。

基于这种把树变矮胖,从而减少树的层数的思想,我们设计了B树。

6.4 B树

B树的英文是Blance Tree,又称为多路平衡查找树。B树的结构如下图。

我们可以观察下它的特点。上面磁盘块1中有两个元素,分别是17和35,磁盘块2的元素都小于17,磁盘块3的元素位于17与35之间,磁盘块4的元素都大于35.

在一棵B树中,子结点数量的最大值称为,上图中B树的阶为3.

我们不妨回顾下B+树,然后看看B树与B+树有何不同。

我们看到,页30的节点中存储了index和page_no,而它的子结点页10则存储了具体的记录数据。但B树的叶子节点与非叶子节点存储的信息都完全独立。换句话说,B树的节点不存在上下级关系。如果使用B树作为索引的数据结构,我们需要在每个节点中存储完整的记录信息。

B树具有如下特性。

  • 如果插入数据、删除数据导致树不平衡,会自动调整至平衡。
  • 关键字集合在整个树中,即叶子节点与非叶子节点都存放数据,搜索可能在叶子节点中结束。

6.6 B+树

B+树其实是在B树的基础上进行的改进。B+树更加适合文件索引的系统。现在总结下B树与B+树的区别。

在B+树中,一个节点有k个孩子(子结点)就有k个关键字(data),而在B树中,一个节点的孩子树=关键字数+1。

B+树非叶子节点只用于索引,不存储数据.而B树中各个节点存储的都独立存储数据。

B+树所有关键字都在叶子节点出现,并且叶子节点之间通过双向链表来彼此链接,叶子节点内的数据按照顺序使用单链表连接。


上面我们提到了B+树的中间节点只用于索引,不存储数据,这有什么好处呢?


B+树的查询效率更加稳定。每次查找的I/O次数更少。

B+树的查询时I/O次数更少,查询效率更快。因为B+树的非叶子节点只用于索引,不存储数据的信息,就可以有更多的子树,这会使其更加矮胖,也就是阶数更低,查询时I/O次数更少。

B+树的范围查询效率更高,由于B+树的叶子节点存储了所有的记录信息,并且是按照顺序排列,我们在查找时通过链表指针就可以快速进行范围查询了。


6.7 R树

另外对于地图等高维搜索空间问题一般使用R树作为索引的数据结构,MySQL不支持使用R树作为索引。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
9天前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
76 9
|
13天前
|
缓存 关系型数据库 MySQL
MySQL 索引优化以及慢查询优化
通过本文的介绍,希望您能够深入理解MySQL索引优化和慢查询优化的方法,并在实际应用中灵活运用这些技术,提升数据库的整体性能。
54 18
|
6天前
|
存储 Oracle 关系型数据库
索引在手,查询无忧:MySQL索引简介
MySQL 是一款广泛使用的关系型数据库管理系统,在2024年5月的DB-Engines排名中得分1084,仅次于Oracle。本文介绍MySQL索引的工作原理和类型,包括B+Tree、Hash、Full-text索引,以及主键、唯一、普通索引等,帮助开发者优化查询性能。索引类似于图书馆的分类系统,能快速定位数据行,极大提高检索效率。
32 8
|
12天前
|
缓存 关系型数据库 MySQL
MySQL 索引优化以及慢查询优化
通过本文的介绍,希望您能够深入理解MySQL索引优化和慢查询优化的方法,并在实际应用中灵活运用这些技术,提升数据库的整体性能。
18 7
|
11天前
|
缓存 关系型数据库 MySQL
MySQL 索引优化与慢查询优化:原理与实践
通过本文的介绍,希望您能够深入理解MySQL索引优化与慢查询优化的原理和实践方法,并在实际项目中灵活运用这些技术,提升数据库的整体性能。
41 5
|
15天前
|
存储 关系型数据库 MySQL
Mysql索引:深入理解InnoDb聚集索引与MyisAm非聚集索引
通过本文的介绍,希望您能深入理解InnoDB聚集索引与MyISAM非聚集索引的概念、结构和应用场景,从而在实际工作中灵活运用这些知识,优化数据库性能。
79 7
|
1天前
|
存储 关系型数据库 MySQL
【MYSQL】 ——索引(B树B+树)、设计栈
索引的特点,使用场景,操作,底层结构,B树B+树,MYSQL设计栈
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
210 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
35 1
|
27天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
53 5

热门文章

最新文章