最近花了大概一周的时间重新深入研究了一遍MySQL的内容,近期可能会输出一些关于MySQL方面的知识干货,希望各位读者喜欢。
什么是索引?为什么要建立索引?
关于索引的理解,个人更加喜欢将其比喻为字典里面的目录,根据字典来进行查询的速度远大于每一页逐个逐个字排查的速度。
索引主要用于快速找出在某个列中有特定值的行,倘若不使用索引,MySQL必须从第一条记录开始读完整个表,直到找出相关的行,表越大,查询数据所花费的时间就越多。如果表中查询的列有一个索引,MySQL能够快速到达一个位置去搜索数据,而不必查找所有数据,那么将会节省很大一部分时间。
索引的存储文件是如何的?
首先我们来看看mysql索引数据的存储位置:
mysql的数据存储是存放在mysql的data文件夹底下,截图如下所示:
查看该文件夹底下,我们通常可以看到相关的信息内容:
.frm表结构文件,和所选用的存储引擎无关。
MyISAM引擎的文件格式
.myd 数据文件后缀
.myi 索引文件后缀
InnoDB引擎的文件格式
.ibd 将索引信息和数据一起存储起来
索引的结构是什么?为何不采用别的结构?
索引在起初做设计的时候其实是有一定数据结构选型的,对于不同的数据结构基础,我做了以下的相关总结:
1.使用二叉树作为索引结构缺陷
容易导致二叉树出现结构偏移,极端情况容易变成一条链表的形状。
例如下方情况:
2.使用红黑树数据结构的缺陷
红黑树虽然有自动进行树节点的二叉平衡功能。虽然相对于二叉树而言,不会有太严重的单边偏移情况,但还是避免不了极端情况下树的重心出现偏移的现象。(数据量变大的情况下,深度会变大)
使用红黑树数据结构容易在极端的情况下发生红黑树失重情况,如下图所示,随着数据量的增大,失重情况愈发严重:
3.hash索引的缺陷
虽然说hash查询的速度很快,但是依然有以下缺陷:
- 无法解决查询范围导致的问题
- 无法解决hash冲突的问题
如何理解BTree?
在学习索引的真正结构之前,首先我们需要来了解一下什么是BTree。
BTree的基本结构如下图所示:
BTree里面包含有几个重要的特点
- 度(Degree)-节点的数据存储个数,一旦存储数据超过度值就要进行节点分裂
- 所有叶子节点具有相同的深度
- 叶子节点的指针为空
- 叶子节点中的数据key从左到右递增排列
btree数据结构通过节点的横向扩展,从而压低整个Btree的高度,减少了节点io读取的次数。通常百万级别的数据会被压到3-5层的高度。
节点数据读取过程发生了什么?
我在初学索引的时候,觉得io次数读取越少,因此获取数据的速度会越快。后来重新回看了一遍操作系统原理的讲解之后,对于这块的内容有了更加深入的认识。
磁盘数据读取
指针在同一磁道上边读取数据的时候如果采用的是顺序读取方式,那么数据的读取效率就会比较高效。倘若数据在进行读取的时候采用了随机读取的方式,则需要进行磁道的变换,这种磁道变换读取所带来的性能消耗会是巨大的。每个节点存放的地址通常都不会是连续的,不可避免的会有一些内存碎片存在,因此每一次进行io读取都会是比较耗费性能的。
btree里面的节点采用了key-value的基本存储结构,key是索引的数值,value是存储的data数值。由于我们对于btree进行节点比较的时候是基于内存进行数据比较,先从磁盘进行io读取数据,读取到cpu缓存中进行比对。在了解了磁道读取问题之后,我们再来思考一下索引的遍历。如下图所示:
如图所示,假设我们没有采用索引,要读取数据第七行(23),则需要进行7次的io读取操作。假若使用了索引,则可以通过走索引的方式,34-->22-->23一共三次io读取操作即可查找到所要的节点23。
度值无限扩增会如何?
如果我们将节点的度设置到极致,例如说将度设置到100W,那么BTree的高度就会降低,查询的次数就会大大减少,是否可行?
这种想法是不可行的,节点会变得过大。每次进行节点数据读取的时候都需要将磁盘的数据加载到操作系统自身的缓存中。假设将度值设置过大,io一次读取的大小还是有限,过大的节点还是需要进行多次的io读取。
计算机里面的内存和磁盘之间进行数据读取是按照计算机自身标准来进行设置的,每次读取的大小空间基本单位通常称之为页,假设每一页的数据读取通常是8k(不同硬件设备大小不同),假若说一个节点的大小为10M,那么读取该节点里面的数据则需要进行多次的io操作。 (通常DBA在进行数据库的度值设置的时候默认是将一个页单位的大小设置为度的大小。)