十三、mysql索引

转载至链接:https://blog.csdn.net/alex_xfboy/article/details/82818753
提到数据库索引,我想你并不陌生,在日常工作中会经常接触到。比如某一个 SQL 查询比较慢,分析完原因之后,你可能就会说“给某个字段加个索引吧”之类的解决方案。但到底什么是索引,索引又是如何工作的呢?今天就让我们一起来聊聊这个话题吧。
一句话简单来说,索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。一本 500 页的书,如果你想快速找到其中的某一个知识点,在不借助目录的情况下,那我估计你可得找一会儿。同样,对于数据库的表而言,索引其实就是它的“目录”。
索引是帮助数据库系统高效获取数据的数据结构,索引可以帮助我们快速地定位到数据而不需要每次搜索的时候都遍历数据库中的每一行。其本质是一种数据结构,既然是一种数据结构自然要涉及到在物理介质上的存储,以增加额外用于维护索引数据结构的存储空间为代价,换取数据库中数据检索效率的提升。

一、索引的数据结构

索引的出现是为了提高查询效率,可以用于提高读写效率的数据结构很多,常见的有哈希表、有序数组和二查树、红黑树、B+树等。
可以通过如下网站可视化各种树的构造过程:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

1.1 哈希表

在这里插入图片描述
哈希表是一种以键 - 值(key-value)存储数据的结构,我们只要输入待查找的 key,就可以找到其对应的值即 Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把 key 换算成一个确定的位置,然后把 value 放在数组的这个位置。
不可避免地,多个 key 值经过哈希函数的换算,会出现同一个值的情况。处理这种情况的一种方法是,拉出一个链表。
如上图所示,我们将一系列的键值key通过哈希函数,得到hash码,基于hash码找到在桶上的位置,桶中每个元素存储了value链的存储地址。
hash表的搜索时间复杂度为o(1),效率非常高,但是mysql底层并没有使用哈希索引,这是因为,相等性查询(如id=4)时能很快检索,但是不等性查询(如id<4)等范围方式查找,无法快速定位地址。

1.2 二叉树

在这里插入图片描述
二叉树的特点是:左中右 ,小中大;即左子节点小于父节点,父节点小于右子节点。
平衡二叉树定义(AVL):它或者是一颗空树,或者具有以下性质的二叉排序树:它的左子树和右子树的深度之差(平衡因子)的绝对值不超过1,且它的左子树和右子树都是一颗平衡二叉树。
棵AVL树有如下必要条件:
条件一:它必须是二叉查找树。
条件二:每个节点的左子树和右子树的高度差至多为1。
在这里插入图片描述
图一中左边二叉树的节点45的左孩子46比45大,不满足二叉搜索树的条件,因此它也不是一棵平衡二叉树。右边二叉树满足二叉搜索树的条件,同时它满足条件二,因此它是一棵平衡二叉树。
在这里插入图片描述
左边二叉树的节点45左子树高度2,右子树高度0,左右子树高度差为2-0=2,不满足条件二;右边二叉树的节点均满足左右子树高度差至多为1,同时它满足二叉搜索树的要求,因此它是一棵平衡二叉树。
如果mysql中的数据列构成的索引形成平衡二叉树,那么查询效率比较高。但是数据的插入对树的结构有很大影响,不一定会形成平衡二叉树,比如:自增列,不断插入过程中最终形成如下结构:
在这里插入图片描述
是一颗倾斜二叉树,基于此树查询时,需要不断遍历每个节点,索引并没有起到作用。
因此,mysql底层没有使用二叉树作为索引数据结构。

1.3 红黑树

参考:http://www.360doc.com/content/18/0904/19/25944647_783893127.shtml
mysql并没有使用红黑树作为索引的数据结构。相对于二叉树,只是做到了相对平衡,没有做到绝对平衡,没有实际解决二叉树的确点。
在这里插入图片描述

1.4 B+Tree

目前大多数数据库系统及文件系统都采用 B-Tree 或其变种 B+Tree 作为索引结构。B+ 树中的 B (balance)代表平衡,而不是二叉。B+ 树是从最早的平衡二叉树演化而来的。B+ 树是由二叉查找树、平衡二叉树(AVLTree)和平衡多路查找树(B-Tree)逐步优化而来。
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘 I/O 消耗,相对于内存存取,I/O 存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘 I/O 操作次数的渐进复杂度。换句话说,索引的结构组织要尽量减少查找过程中磁盘 I/O 的存取次数

利用网站制作的B+Tree:
在这里插入图片描述
可以看到,数据都在叶子节点上,并且叶子节点用指针串联起来了,在遍历的时候更快些。
在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息

二、mysql索引的使用

存储引擎是作用于表上的,目前比较常用的为MYISAM和InnoDB

2.1 MyISAM的非聚集索引

那么在MyISAM中是如何利用B+Tree索引组织数据的呢?什么是非聚集索引呢?

使用MyISAM引擎储存表数据会产生三个文件: .frm .MYD .MYI
如下图:ti为表名, .frm是存放表的定义信息(MyISAM和innoDB都有这个文件),
.MYD是存放具体的表的数据 ,.MYI就是存放该表的所有索引
在这里插入图片描述
那什么又是非聚集索引呢?简单来说就是索引文件和数据文件分开存储,索引树的叶子节点保存对应数据的地址,假设table表 有主键id和name(name列已经建立了索引),下面画图说明问题:

首先准备数据
在这里插入图片描述
对创建name列创建索引

create index idx_name on ti(name);
show index from ti;

在这里插入图片描述
下面这张图就表面了在MyISAM下索引是如何工作的
在这里插入图片描述

信息量非常大,我来一一说明:这个索引树是以建立索引的列的所有数据组织起来的,可以看出索引十分消耗存储空间,而且叶子节点存储的是对应的那行数据的地址,查找的时候先通过索引树找到对应数据的地址,再通过地址找到真正的数据。这也就是为什么不把全部的索引一次性载入内存的原因, 索引太大了。

4.innoDB的聚集索引
innoDB的索引树和MyISAM是有区别的,索引和数据放在同一个文件里面。创建表是,生成的是两个文件:.frm和.ibd, .frm是存放表的定义信息(MyISAM和innoDB都有这个文件),.ibd是用来存储数据和索引的
主键索引树的叶子节点直接存储数据,所以叫做聚合索引。假设上面的表用的是InnoDB,建立了主键id索引和name这一列的索引,那么数据又是如何组织起来的呢,下面画图说明:

在这里插入图片描述

可以看到在主键索引的叶子节点上直接存储了对应的数据数据和索引在一起,聚合索引。而且其他的索引树的叶子节点对应的是该行数据的主键id,如果以name进行查找,先在name的索引树上找到对应的主键id,再通过得到的id进行查找。这样是为什么innoDB查询的时候比MyISAM慢的原因之一,innoDB必须涉及到主键索引,即占用内存又直接多了一次主键索引树的查找。

B+Tree的特性

(1)由图能看出,单节点能存储更多数据,使得磁盘IO次数更少。

(2)叶子节点形成有序链表,便于执行范围操作。

(3)聚集索引中,叶子节点的data直接包含数据;非聚集索引中,叶子节点存储数据地址的指针。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章