MySQL 数据库索引原理与分类

转载:https://www.jianshu.com/p/e1dce41a6b2b

前言


数据库索引本质上是一种数据结构(存储结构+算法),目的是为了加快目标数据检索的速度。

目录


1.索引的本质与原理?
2.索引的分类?

3、索引的实现方式

1.索引的本质与原理


我们先看一个问题:

假设现在有100000条从0到10000且从大到小排列的整型数据,1条数据的大小假设(真的只是假设)是1KB,操作系统的每次I/O数据块(页)大小是8KB。
如果现在我要查找其中 50001 这个数据值,有如下几个方式:
1.最蠢的方式,遍历,每次遍历到一个值,就用这个值跟目标值做对比,如果不等于那么查找下一个。这样的话那么每次I/O是8条数据,目标数据在50001/8 约6600多次I/O 才能找到目标数据。
2.二分查找,最好一次性将100000条数据全部读到内存,这样查找也是很快的。

但是即使二分查找很快,但这些数据也不能单单通过一次I/O全部进入内存,进行运算。

那么怎样在I/O 块大小 的限制下快速利用二分查找找到目标值呢?我们得引入新的数据结构,B+树正好可以解决上述I/O块大小的限制,解决限制不是说增大了限制范围,而是我们在此限制上改变了数据的存储结构,即在同等限制条件下,快速检索到目标数据,如下是B+树的原理讲解:

注意,我们主要讲解索引的原理,没有必要过于纠结B+树的各种操作,及代码实现

1.1 B+ 树

B+树图示


根据上图所示,及其论文定义:

1.图上蓝色的块为关键字,我们发现所有的关键字最终都会被包含在叶子节点当中。
图上的黄色区块表示的是子树的指针域,比如根节点下的P2指向的就是28-65之间的索引。


2.所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,
且叶子结点本身依关键字的大小自小而大的顺序链接。 (而B 树的叶子节点并没有包括全部需要查找的信息)


3.所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。 (而B 树的非终节点也包含需要查找的有效信息)

现在我们来看下查找数据 60 的 查找过程,如下所示:

1.I/O第一次:读入5、28、65 数据块,在此同级别节点块上,60在28到65之间(其实是二分查找),那走P2指针指向的子树。
2.I/O第二次:读入28、35、56 数据块,在此同级别节点块上,60大于56,所以走P3指针指向的子树(上图中就是叶子节点)。
3.I/O第三次:读入叶子节点,在这个叶子节点中,使用二分查找算法找到目标值60。

由上述查找过程所示统共需要三次I/O就能查到目标值,性能大大提升。

2.索引的分类?


2.1 聚簇索引 & 非聚簇索引

InnoDB 主键使用的是聚簇索引,MyISAM 不管是主键索引,还是二级索引使用的都是非聚簇索引。

下图形象说明了聚簇索引表(InnoDB)和非聚簇索引(MyISAM)的区别:

聚簇索引与非聚簇索引


1.对于非聚簇索引表来说(右图),表数据和索引是分成两部分存储的,主键索引和二级索引存储上没有任何区别。使用的是B+树作为索引的存储结构,所有的节点都是索引,叶子节点存储的是索引+索引对应的记录的地址。


2.对于聚簇索引表来说(左图),表数据是和主键一起存储的,主键索引的叶结点存储行数据(包含了主键值),二级索引的叶结点存储行的主键值。使用的是B+树作为索引的存储结构,非叶子节点都是索引关键字,但非叶子节点中的关键字中不存储对应记录的具体内容或内容地址。叶子节点上的数据是主键与具体记录(数据内容)。

聚簇索引的优点

1.当你需要取出一定范围内的数据时,用聚簇索引也比用非聚簇索引好。
2.当通过聚簇索引查找目标数据时理论上比非聚簇索引要快,因为非聚簇索引定位到对应主键时还要多一次目标记录寻址,即多一次I/O。

聚簇索引的缺点

1.插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键。

2.更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。
3.二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。
二级索引的叶节点存储的是主键值,而不是行指针(非聚簇索引存储的是指针或者说是地址),这是为了减少当出现行移动或数据页分裂时二级索引的维护工作,但会让二级索引占用更多的空间。
4.采用聚簇索引插入新值比采用非聚簇索引插入新值的速度要慢很多,因为插入要保证主键不能重复,判断主键不能重复,采用的方式在不同的索引下面会有很大的性能差距,聚簇索引遍历所有的叶子节点,非聚簇索引也判断所有的叶子节点,但是聚簇索引的叶子节点除了带有主键还有记录值,记录的大小往往比主键要大的多。这样就会导致聚簇索引在判定新记录携带的主键是否重复时进行昂贵的I/O代价。

唯一索引

主键就是唯一索引,但是唯一索引不一定是主键,唯一索引可以为空,但是空值只能有一个,主键不能为空。
普通唯一索引:单个字段上建立唯一索引,需要此字段所在的列上不能有重复的值,属于二级索引。
复合唯一索引:多个字段上联合建立唯一索引,属于二级索引。

覆盖索引

查找的目标数据, 包含在索引中,如建立idx_colum1_colum2.

select colum1 from table where colum1 = ? and colum2 > ?

通过查询索引就能确定最终的数据,不用再利用叶子节点中存储的主键值去查询对应的数据。
覆盖索引的性能是极高的。

3、索引的实现方式

1 B+树
    我们经常听到B+树就是这个概念,用这个树的目的和红黑树差不多,也是为了尽量保持树的平衡,当然红黑树是二叉树,但B+树就不是二叉树了,节点下面可以有多个子节点,数据库开发商会设置子节点数的一个最大值,这个值不会太小,所以B+树一般来说比较矮胖,而红黑树就比较瘦高了。
关于B+树的插入,删除,会涉及到一些算法以保持树的平衡,这里就不详述了。ORACLE的默认索引就是这种结构的。
如果经常需要同时对两个字段进行AND查询,那么使用两个单独索引不如建立一个复合索引,因为两个单独索引通常数据库只能使用其中一个,而使用复合索引因为索引本身就对应到两个字段上的,效率会有很大提高。


2 散列索引
    第二种索引叫做散列索引,就是通过散列函数来定位的一种索引,不过很少有单独使用散列索引的,反而是散列文件组织用的比较多。
散列文件组织就是根据一个键通过散列计算把对应的记录都放到同一个槽中,这样的话相同的键值对应的记录就一定是放在同一个文件里了,也就减少了文件读取的次数,提高了效率。
散列索引呢就是根据对应键的散列码来找到最终的索引项的技术,其实和B树就差不多了,也就是一种索引之上的二级辅助索引,我理解散列索引都是二级或更高级的稀疏索引,否则桶就太多了,效率也不会很高。


3 位图索引
    位图索引是一种针对多个字段的简单查询设计一种特殊的索引,适用范围比较小,只适用于字段值固定并且值的种类很少的情况,比如性别,只能有男和女,或者级别,状态等等,并且只有在同时对多个这样的字段查询时才能体现出位图的优势。
位图的基本思想就是对每一个条件都用0或者1来表示,如有5条记录,性别分别是男,女,男,男,女,那么如果使用位图索引就会建立两个位图,对应男的10110和对应女的01001,这样做有什么好处呢,就是如果同时对多个这种类型的字段进行and或or查询时,可以使用按位与和按位或来直接得到结果了。


B+树最常用,性能也不差,用于范围查询和单值查询都可以。特别是范围查询,非得用B+树这种顺序的才可以了。
HASH的如果只是对单值查询的话速度会比B+树快一点,但是ORACLE好像不支持HASH索引,只支持HASH表空间。
位图的使用情况很局限,只有很少的情况才能用,一定要确定真正适合使用这种索引才用(值的类型很少并且需要复合查询),否则建立一大堆位图就一点意义都没有了。


索引原理篇讲述完,下一篇讲解索引的优化,以及 explain 工具的使用。



作者:fxliutao
链接:https://www.jianshu.com/p/e1dce41a6b2b
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自blog.csdn.net/dhfzhishi/article/details/80329425
今日推荐