目录
索引是什么?
索引定义
索引类型
索引存储模型推演
二分查找
二叉查找树( Binary Search Tree)
平衡二叉树(AVL Tree)
多路平衡查找树(B Tree)
B+树(加强版B Tree)
后记
首页 数据库 mysql教程 MySQL中什么是索引?索引存储模型浅析

MySQL中什么是索引?索引存储模型浅析

Oct 18, 2021 pm 07:24 PM
mysql 索引

下面mysql教程栏目带大家深入剖析下MySQL中的索引,介绍一下MySQL索引的一些知识,希望对大家有所帮助!

MySQL中什么是索引?索引存储模型浅析

MySQL 数据库应该是最常用的数据库之一,在各种大大小小的公司都可以看到它的身影,你对 MySQL 数据库掌握的如何呢?想要更好的使用它,那么我们就必须先了解它,正所谓的工欲善其事,必先利其器

本篇文章就带领大家一起来深入剖析MySQL索引的一些知识,先来了解什么是索引,以及索引存储模型的推演,底层数据结构为什么会选择B+树其缘由?

索引是什么?

一张表有 500 万条数据,在没有索引的 name 字段上执行一条 where 查询:

select * from user_innodb where name ='小马';
登录后复制

如果 name 字段上面有索引呢?在 name 字段上面创建一个索引,再来执行一下相同的查询。

ALTER TABLE user_innodb DROP INDEX idx_name; 
ALTER TABLE user_innodb ADD INDEX idx_name (name);
登录后复制

有索引的查询和没有索引的查询相比,效率相差几十倍。

通过这个案例大家应该可以非常直观地感受到,索引对于数据检索的性能改善是非常大的。

那么索引到底是什么呢?为什么可以对我们的查询产生这么大的影响?创建索引的时候发生了什么事情?

索引定义

数据库索引,是数据库管理系统(DBMS)中一个排序的数据结构,以协助快速查询、更新数据库表中数据。

image-20211014152406430

数据是以文件的形式存放在磁盘上面的,每一行数据都有它的磁盘地址。如果没有索引的话,我们要从 500 万行数据里面检索一条数据,只能依次遍历这张表的全部数据,直到找到这条数据。

但是我们有了索引之后,只需要在索引里面去检索这条数据就行了,因为它是一种特殊的专门用来快速检索的数据结构,我们找到数据存放的磁盘地址以后,就可以拿到数据了。

索引类型

在 InnoDB 里面,索引类型有三种:普通索引、唯一索引(主键索引是特殊的唯一索引)、全文索引。

普通(Normal):也叫非唯一索引,是最普通的索引,没有任何的限制。

唯一(Unique):唯一索引要求键值不能重复。另外需要注意的是,主键索引是一种特殊的唯一索引,它还多了一个限制条件,要求键值不能为空。主键索引用 primay key 创建。

全文(Fulltext):针对比较大的数据,比如我们存放的是消息内容,有几 KB 的数据的这种情况,如果要解决 like 查询效率低的问题,可以创建全文索引。只有文本类型的字段才可以创建全文索引,比如 char、varchar、text。

索引是一种数据结构,那么它到底应该选择一种什么数据结构,才能实现数据的高效检索呢?

索引存储模型推演

二分查找

双十一过去之后,你女朋友跟你玩了一个猜数字的游戏。 猜猜我昨天买了多少钱,给你五次机会。

10000?低了。30000?高了。接下来你会猜多少? 20000。为什么你不猜 11000,也不猜 29000 呢?

这个就是二分查找的一种思想,也叫折半查找,每一次,我们都把候选数据缩小了 一半。如果数据已经排过序的话,这种方式效率比较高。

所以第一个,我们可以考虑用有序数组作为索引的数据结构。

有序数组的等值查询和比较查询效率非常高,但是更新数据的时候会出现一个问题,可能要挪动大量的数据(改变 index),所以只适合存储静态的数据。

为了支持频繁的修改,比如插入数据,我们需要采用链表。链表的话,如果是单链表,它的查找效率还是不够高。

所以,有没有可以使用二分查找的链表呢?

为了解决这个问题,BST(Binary [ˈbaɪnəri] Search Tree)也就是我们所说的二叉查找树诞生了。

二叉查找树( Binary Search Tree)

左子树所有的节点都小于父节点,右子树所有的节点都大于父节点。投影到平面以后,就是一个有序的线性表。

image-20211014155654921

二叉查找树既能够实现快速查找,又能够实现快速插入。

但是二叉查找树有一个问题:查找耗时是和这棵树的深度相关的,在最坏的情况下时间复杂度会退化成 O(n)。

什么情况是最坏的情况呢?

还是刚才的这一批数字,如果我们插入的数据刚好是有序的,2、10、12、15、 21、28

这个时候 BST 会变成链表( “斜树”),这种情况下不能达到加快检索速度的目的,和顺序查找效率是没有区别的。

image-20211014162114680

造成它倾斜的原因是什么呢?

因为左右子树深度差太大,这棵树的左子树根本没有节点——也就是它不够平衡。

所以,我们有没有左右子树深度相差不是那么大,更加平衡的树呢?

这个就是平衡二叉树,叫做 Balanced binary search trees,或者 AVL 树。

平衡二叉树(AVL Tree)

平衡二叉树的定义:左右子树深度差绝对值不能超过 1。

是什么意思呢?比如左子树的深度是 2,右子树的深度只能是 1 或者 3。

这个时候我们再按顺序插入 1、2、3、4、5、6,一定是这样,不会变成一棵“斜树”。

image-20211014162322998

那 AVL 树的平衡是怎么做到的呢?怎么保证左右子树的深度差不能超过 1 呢? 例如:插入 1、2、3。

当我们插入了 1、2 之后,如果按照二叉查找树的定义,3 肯定是要在 2 的右边的,这个时候根节点 1 的右节点深度会变成 2,但是左节点的深度是 0,因为它没有子节点,所以就会违反平衡二叉树的定义。

那应该怎么办呢?因为它是右节点下面接一个右节点,右-右型,所以这个时候我们要把 2 提上去,这个操作叫做左旋。

image-20211014163132830

同样的,如果我们插入 7、6、5,这个时候会变成左左型,就会发生右旋操作,把 6 提上去。

image-20211014163348892

所以为了保持平衡,AVL 树在插入和更新数据的时候执行了一系列的计算和调整的操作。

平衡的问题我们解决了,那么平衡二叉树作为索引怎么查询数据? 在平衡二叉树中,一个节点,它的大小是一个固定的单位,作为索引应该存储什么内容?

第一个:索引的键值。比如我们在 id 上面创建了一个索引,我在用 where id =1 的条件查询的时候就会找到索引里面的 id 的这个键值。

第二个:数据的磁盘地址,因为索引的作用就是去查找数据的存放的地址。

第三个因为是二叉树,它必须还要有左子节点和右子节点的引用,这样我们才能找到下一个节点。比如大于 26 的时候,走右边,到下一个树的节点,继续判断。

image-20211014174659853

如果是这样存储数据的话,我们来看一下会有什么问题。

首先,索引的数据,是放在硬盘上的。查看数据和索引的大小:

select CONCAT(ROUND(SUM(DATA_LENGTH/1024/1024),2),'MB') AS data_len, 
CONCAT(ROUND(SUM(INDEX_LENGTH/1024/1024),2),'MB') as index_len 
from information_schema.TABLES 
where table_schema='gupao' and table_name='user_innodb';
登录后复制

当我们用树的结构来存储索引的时候,因为拿到一块数据就要在 Server 层比较是不是需要的数据,如果不是的话就要再读一次磁盘。访问一个节点就要跟磁盘之间发生一次 IO。InnoDB 操作磁盘的最小的单位是一页(或者叫一个磁盘块),大小是 16K(16384 字节)。

那么,一个树的节点就是 16K 的大小。 如果我们一个节点只存一个键值+数据+引用,例如整形的字段,可能只用了十几个或者几十个字节,它远远达不到 16K 的容量,所以访问一个树节点,进行一次 IO 的时候,浪费了大量的空间。

所以如果每个节点存储的数据太少,从索引中找到我们需要的数据,就要访问更多的节点,意味着跟磁盘交互次数就会过多。

如果是机械硬盘时代,每次从磁盘读取数据需要 10ms 左右的寻址时间,交互次数越多,消耗的时间就越多。

比如上面这张图,我们一张表里面有 6 条数据,当我们查询 id=37 的时候,要查询两个子节点,就需要跟磁盘交互 3 次,如果我们有几百万的数据呢?这个时间更加难以估计。

所以我们的解决方案是什么呢?

第一个,就是让每个节点存储更多的数据。

第二个,节点上的关键字的数量越多,我们的指针数也越多,也就是意味着可以有更多的分叉。

因为分叉数越多,树的深度就会减少(根节点是 0)。这样,我们的树是不是从原来的高瘦高瘦的样子,变成了矮胖矮胖的样子?

这个时候,我们的树就不再是二叉了,而是多叉,或者叫做多路。

多路平衡查找树(B Tree)

跟 AVL 树一样,B 树在枝节点和叶子节点存储键值、数据地址、节点引用。

它有一个特点:分叉数(路数)永远比关键字数多 1。比如我们画的这棵树,每个节点存储两个关键字,那么就会有三个指针指向三个子节点。

image-20211014165736948

B Tree 的查找规则是什么样的呢?

比如我们要在这张表里面查找 15。 因为 15 小于 17,走左边。 因为 15 大于 12,走右边。 在磁盘块 7 里面就找到了 15,只用了 3 次 IO。

这个是不是比 AVL 树效率更高呢? 那 B Tree 又是怎么实现一个节点存储多个关键字,还保持平衡的呢?跟 AVL 树有什么区别?

比如 Max Degree(路数)是 3 的时候,我们插入数据 1、2、3,在插入 3 的时候,本来应该在第一个磁盘块,但是如果一个节点有三个关键字的时候,意味着有 4 个指针, 子节点会变成 4 路,所以这个时候必须进行分裂(其实就是 B+Tree)。把中间的数据 2 提上去,把 1 和 3 变成 2 的子节点。

如果删除节点,会有相反的合并的操作。

注意这里是分裂和合并,跟 AVL 树的左旋和右旋是不一样的。

我们继续插入 4 和 5,B Tree 又会出现分裂和合并的操作。

image-20211014165954674

从这个里面我们也能看到,在更新索引的时候会有大量的索引的结构的调整,所以解释了为什么我们不要在频繁更新的列上建索引,或者为什么不要更新主键。

节点的分裂和合并,其实就是 InnoDB 页(page)的分裂和合并。

B+树(加强版B Tree)

B Tree 的效率已经很高了,为什么 MySQL 还要对 B Tree 进行改良,最终使用了 B+Tree 呢?

总体上来说,这个 B 树的改良版本解决的问题比 B Tree 更全面。

我们来看一下 InnoDB 里面的 B+树的存储结构:

image-20211014170414762

MySQL 中的 B+Tree 有几个特点:

  1. 它的关键字的数量是跟路数相等的;

  2. B+Tree 的根节点和枝节点中都不会存储数据,只有叶子节点才存储数据。搜索到关键字不会直接返回,会到最后一层的叶子节点。比如我们搜索 id=28,虽然在第一层直接命中了,但是全部的数据在叶子节点上面,所以我还要继续往下搜索,一直到叶子节点。

  3. B+Tree 的每个叶子节点增加了一个指向相邻叶子节点的指针,它的最后一个数据会指向下一个叶子节点的第一个数据,形成了一个有序链表的结构。

  4. 它是根据左闭右开的区间 [ )来检索数据。

B+Tree 的数据搜寻过程:

  1. 比如我们要查找 28,在根节点就找到了键值,但是因为它不是页子节点,所以会继续往下搜寻,28 是[28,66)的左闭右开的区间的临界值,所以会走中间的子节点,然后继续搜索,它又是[28,34)的左闭右开的区间的临界值,所以会走左边的子节点,最后在叶子节点上找到了需要的数据。

  2. 第二个,如果是范围查询,比如要查询从 22 到 60 的数据,当找到 22 之后,只需要顺着节点和指针顺序遍历就可以一次性访问到所有的数据节点,这样就极大地提高了区间查询效率(不需要返回上层父节点重复遍历查找)。

InnoDB 中的 B+Tree 的特点:

  1. 它是 B Tree 的变种,B Tree 能解决的问题,它都能解决。B Tree 解决的两大问题是什么?(每个节点存储更多关键字;路数更多) ;

  2. 扫库、扫表能力更强(如果我们要对表进行全表扫描,只需要遍历叶子节点就可以了,不需要遍历整棵 B+Tree 拿到所有的数据) ;

  3. B+Tree 的磁盘读写能力相对于 B Tree 来说更强(根节点和枝节点不保存数据区,所以一个节点可以保存更多的关键字,一次磁盘加载的关键字更多) ;

  4. 排序能力更强(因为叶子节点上有下一个数据区的指针,数据形成了链表) ;

  5. 效率更加稳定(B+Tree 永远是在叶子节点拿到数据,所以 IO 次数是稳定的)。

后记

看到这里,相信小伙伴应该都知道了MySQL为什么选择使用 B+ 树作为索引的数据结构模型。

更多编程相关知识,请访问:编程入门!!

以上是MySQL中什么是索引?索引存储模型浅析的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

mysql:简单的概念,用于轻松学习 mysql:简单的概念,用于轻松学习 Apr 10, 2025 am 09:29 AM

MySQL是一个开源的关系型数据库管理系统。1)创建数据库和表:使用CREATEDATABASE和CREATETABLE命令。2)基本操作:INSERT、UPDATE、DELETE和SELECT。3)高级操作:JOIN、子查询和事务处理。4)调试技巧:检查语法、数据类型和权限。5)优化建议:使用索引、避免SELECT*和使用事务。

phpmyadmin怎么打开 phpmyadmin怎么打开 Apr 10, 2025 pm 10:51 PM

可以通过以下步骤打开 phpMyAdmin:1. 登录网站控制面板;2. 找到并点击 phpMyAdmin 图标;3. 输入 MySQL 凭据;4. 点击 "登录"。

MySQL:世界上最受欢迎的数据库的简介 MySQL:世界上最受欢迎的数据库的简介 Apr 12, 2025 am 12:18 AM

MySQL是一种开源的关系型数据库管理系统,主要用于快速、可靠地存储和检索数据。其工作原理包括客户端请求、查询解析、执行查询和返回结果。使用示例包括创建表、插入和查询数据,以及高级功能如JOIN操作。常见错误涉及SQL语法、数据类型和权限问题,优化建议包括使用索引、优化查询和分表分区。

为什么要使用mysql?利益和优势 为什么要使用mysql?利益和优势 Apr 12, 2025 am 12:17 AM

选择MySQL的原因是其性能、可靠性、易用性和社区支持。1.MySQL提供高效的数据存储和检索功能,支持多种数据类型和高级查询操作。2.采用客户端-服务器架构和多种存储引擎,支持事务和查询优化。3.易于使用,支持多种操作系统和编程语言。4.拥有强大的社区支持,提供丰富的资源和解决方案。

redis怎么使用单线程 redis怎么使用单线程 Apr 10, 2025 pm 07:12 PM

Redis 使用单线程架构,以提供高性能、简单性和一致性。它利用 I/O 多路复用、事件循环、非阻塞 I/O 和共享内存来提高并发性,但同时存在并发性受限、单点故障和不适合写密集型工作负载的局限性。

MySQL和SQL:开发人员的基本技能 MySQL和SQL:开发人员的基本技能 Apr 10, 2025 am 09:30 AM

MySQL和SQL是开发者必备技能。1.MySQL是开源的关系型数据库管理系统,SQL是用于管理和操作数据库的标准语言。2.MySQL通过高效的数据存储和检索功能支持多种存储引擎,SQL通过简单语句完成复杂数据操作。3.使用示例包括基本查询和高级查询,如按条件过滤和排序。4.常见错误包括语法错误和性能问题,可通过检查SQL语句和使用EXPLAIN命令优化。5.性能优化技巧包括使用索引、避免全表扫描、优化JOIN操作和提升代码可读性。

MySQL的位置:数据库和编程 MySQL的位置:数据库和编程 Apr 13, 2025 am 12:18 AM

MySQL在数据库和编程中的地位非常重要,它是一个开源的关系型数据库管理系统,广泛应用于各种应用场景。1)MySQL提供高效的数据存储、组织和检索功能,支持Web、移动和企业级系统。2)它使用客户端-服务器架构,支持多种存储引擎和索引优化。3)基本用法包括创建表和插入数据,高级用法涉及多表JOIN和复杂查询。4)常见问题如SQL语法错误和性能问题可以通过EXPLAIN命令和慢查询日志调试。5)性能优化方法包括合理使用索引、优化查询和使用缓存,最佳实践包括使用事务和PreparedStatemen

使用 Redis Exporter 服务监控 Redis Droplet 使用 Redis Exporter 服务监控 Redis Droplet Apr 10, 2025 pm 01:36 PM

有效监控 Redis 数据库对于保持最佳性能、识别潜在瓶颈和确保整体系统可靠性至关重要。 Redis Exporter Service 是一个强大的实用程序,旨在使用 Prometheus 监控 Redis 数据库。 本教程将指导您完成 Redis Exporter Service 的完整设置和配置,确保您无缝建立监控解决方案。通过学习本教程,您将实现完全可操作的监控设置

See all articles