索引以及索引的实现

索引介绍

**索引:**排序形式的数据结构。

在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。

索引的优点:

索引不仅可以加快查询速度,还能避免全表扫描。

减少I/O次数,加快检索速度;根据索引分组和排序,可以加快分组和排序;

索引的缺点:

索引本身是表,因此会占用存储空间,并且索引也会占用磁盘空间。

创建索引时需要对表加锁。

一般来说,索引表占用的空间的数据表的1.5倍;索引表的维护和创建需要时间成本,这个成本随着数据量增大而增大;构建索引会降低数据表的修改操作(删除,添加,修改)的效率,因为在修改数据表的同时还需要修改索引表。

索引的分类

**主键索引:**即主索引,根据主键pk_clolum(length)建立索引,不允许重复,不允许空值

唯一索引:用来建立索引的列的值必须是唯一的,允许空值

**普通索引:**用表中的普通列构建的索引,没有任何限制;

**全文索引:**用大文本对象的列构建的索引;

**组合索引:**用多个列组合构建的索引,这多个列中的值不允许有空值。

索引实现的原理

上面说了索引就是一种数据结构。

一、哈希索引:

只有memory(内存)存储引擎支持哈希索引,哈希索引用索引列的值计算该值的hashCode,然后在hashCode相应的位置存执该值所在行数据的物理位置,因为使用散列算法,因此访问速度非常快,但是一个值只能对应一个hashCode,而且是散列的分布方式,因此哈希索引不支持范围查找和排序的功能。

二、全文索引:

FULLTEXT(全文)索引,仅可用于MyISAM和InnoDB,针对较大的数据,生成全文索引非常的消耗时间和空间。对于文本的大对象,或者较大的CHAR类型的数据,如果使用普通索引,那么匹配文本前几个字符还是可行的,但是想要匹配文本中间的几个单词,那么就要使用LIKE %word%来匹配,这样需要很长的时间来处理,响应时间会大大增加,这种情况,就可使用时FULLTEXT索引了,在生成FULLTEXT索引时,会为文本生成一份单词的清单,在索引时及根据这个单词的清单来索引。FULLTEXT可以在创建表的时候创建,也可以在需要的时候用ALTER或者CREATE INDEX来添加。全文索引的查询也有自己特殊的语法,而不能使用LIKE %查询字符串%的模糊查询语法。

**三、BTree索引:**平衡的多叉查找树/查找复杂度为h*log(n)

设树的度为2d(d>1),高度为h,那么BTree要满足以一下条件:

1.每个叶子结点的高度一样,等于h;
2.每个非叶子结点由n-1个key和n个指针point组成,其中d<=n<=2d,key和point相互间隔,结点两端一定是key;
3.叶子结点指针都为null;
4.非叶子结点的key都是[key,data]二元组,其中key表示作为索引的键,data为键值所在行的数据;

**四、B+Tree索引:**BTree的一个变种

设d为树的度数,h为树的高度,B+Tree和BTree的不同主要在于:

1.B+Tree中的非叶子结点不存储数据,只存储键值;

2.B+Tree的叶子结点没有指针,所有键值都会出现在叶子结点上,且key存储的键值对应data数据的物理地址;

3.B+Tree的每个非叶子节点由n个键值keyn个指针point组成;

MySQL为什么使用B树(B+树)

根据B-Tree的定义,可知检索一次最多需要访问h个节点。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,在实际实现B-Tree还需要使用如下技巧:

每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。

B-Tree中一次检索最多需要h-1次I/O(根节点常驻内存),渐进复杂度为
O(h)=O(logdN) O(h)=O(logdN)
一般实际应用中,出度d是非常大的数字,通常超过100,因此h非常小(通常不超过3)。

(h表示树的高度 & 出度d表示的是树的度,即树中各个节点的度的最大值)

综上所述,用B-Tree作为索引结构效率是非常高的。

而红黑树这种结构,h明显要深的多。由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性,所以红黑树的I/O渐进复杂度也为O(h),效率明显比B-Tree差很多。

上文还说过,B+Tree更适合外存索引,原因和内节点出度d有关。从上面分析可以看到,d越大索引的性能越好,而出度的上限取决于节点内key和data的大小:
dmax=floor(pagesize/(keysize+datasize+pointsize)) dmax=floor(pagesize/(keysize+datasize+pointsize))
floor表示向下取整。由于B+Tree内节点去掉了data域,因此可以拥有更大的出度,拥有更好的性能。

Mysql索引的实现

在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的。

MyISAM索引实现/B+Tree作为索引结构:

MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iShbzZGh-1571272349797)(https://NolanJcn.github.io/pic_lalala/Primarykey_meitu_1.jpg)]

这里设表一共有三列,假设我们以Col1为主键,则上图是一个MyISAM表的主索引(Primary key)示意。可以看出MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。如果我们在Col2上建立一个辅助索引,则此索引的结构如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-55Og84uY-1571272349800)(https://NolanJcn.github.io/pic_lalala/Secondarykey_meitu_2.jpg)]

同样也是一棵B+树,data域保存数据记录的地址。因此,MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。

MyISAM的索引方式也叫做“非聚集”的,之所以这么称呼是为了与InnoDB的聚集索引区分。

InnoDB索引实现/B+Tree作为索引结构:

第一个重大区别是InnoDB的数据文件本身就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Etr0jkDm-1571272349802)(https://NolanJcn.github.io/pic_lalala/Primarykey1_meitu_3.jpg)]

上图是InnoDB主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整型。

第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域。例如,上图为定义在Col3上的一个辅助索引:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TfQS36a4-1571272349802)(https://NolanJcn.github.io/pic_lalala/Secondarykey1_meitu_5.jpg)]

这里以英文字符的ASCII码作为比较准则。聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

了解不同存储引擎的索引实现方式对于正确使用和优化索引都非常有帮助,例如知道了InnoDB的索引实现后,就很容易明白为什么不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。再例如,用非单调的字段作为主键在InnoDB中不是个好主意,因为InnoDB数据文件本身是一棵B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。

参考文章:

https://blog.csdn.net/tongdanping/article/details/79878302#commentBox

https://www.cnblogs.com/boothsun/p/8970952.html#autoid-0-0-0

https://www.cnblogs.com/bnuvincent/p/9011324.html

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