全面解析数据库索引(数据库索引种类大盘点)

前言

前面两篇文章 《解析B+树比B树更加适合做数据库索引的原因 》《从底层解析B+索引提高查询速度的原因》是从数据结构的角度分析了B+索引,并分别介绍了B+索引在两个主流存储引擎InnoDB和MyISAM中的实现。而这篇文章是全面的介绍索引,介绍使用索引的利弊、索引使用时需要注意什么、索引的种类等等。

索引的定义

索引是数据库中用来加快检索速度的数据结构,常用的索引有B+索引和hash索引以及全文索引。

索引使用的利弊以及注意事项

需要使用索引的情况

1、在经常需要搜索的列上建立索引,可以加快搜索的速度;
2、在作为主键的列上建立索引,强制该列的唯一性和组织表中数据的排列结构;
3、在经常用在连接的列上建立索引,这些列主要是一些外键,可以加快连接的速度;
4、在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
5、在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
6、在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。

使用索引的好处

1、减少检索量,提高检索速度, 这是创建索引的最主要的原因。
2、通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
3、使得服务器避免排序和临时表。
4、将随机IO变为顺序IO,顺序1/0不需要多次磁盘寻道,速度更快。
5、可以加速表和表之间的连接。

使用索引的缺点

1、在增删改的时候,可能会破坏索引结构,需要动态维护索引结构,降低了增删改的速度。
2、索引也需要占据物理空间。
3、创建和维护索引都需要耗费时间。

使用索引时的注意事项

1、在使用InnoDB时使用与业务无关的自增主键作为主键,使用逻辑主键,而不要使用业务主键。例如我们可以使用无现实意义的逻辑主键id,而不是具有现实意义的身份证编号作为主键。
2、将打算加索引的列设置为 NOT NULL ,防止引擎放弃使用索引而进行全表扫描。
3、不要在 where 子句中对字段施加函数,这会造成无法命中索引。
4、删除长期未使用的索引,不用的索引的存在会造成不必要的性能损耗。
5、对于中到大型表索引都是非常有效的,但是特大型表的话维护开销会很大,不适合建索引。
6、选择区分度高的列作索引
7、避免冗余索引和重复索引,能扩展就不要新建索引。
8、尽可能的考虑建立联合索引而不是单列索引,索引是需要占用磁盘空间,建立联合而不是建立多个单列可以避免存储空间浪费,避免回表操作。
9、在字符串类型的字段上使用前缀索引代替普通索引,因为前缀索引占用空间少。
10、被频繁更新的字段应该慎重建立索引。
11、不被经常查询的字段没有必要建立索引。
12、表的数据量不够大的情况下,无需建立索引,索引维护和创建都是有开销的。

索引类别

各类索引其实很多是具有交集的,联合索引可以是覆盖索引,主键索引可以是聚集索引也可以是非聚集索引,非聚集索引可以是联合索引,它们并不是相互对立的,而是根据不同的应用情况有着不同的名称。本篇文章主要是从不同的角度对索引的分类进行归纳。

索引按数据结构分类

索引按索引的底层数据结构分类,分为B+索引和hash索引以及全文索引

B+索引

B+索引是数据库使用最多的索引,底层是B+树,以下讨论的索引指的也是B+索引。(若对B+索引不是特别了解,可以看看我的前两篇文章,前言中有链接)

Hash索引

Hash索引的底层是hash表,运用某种哈希算法对索引值进行运算,获得hash值,再通过hash值映射到特定的位置,查找速度及其快。但它只能用于等值查询,无法进行数据库常用的操作-范围查找和排序,而且当记录变多或者索引值重复过多时,容易产生hash碰撞,因此主流的存储引擎都使用B+索引。InnoDB支持自适应Hash索引,也就是说我们不能人为创建hash索引,而是InnoDB引擎进行优化创建hash索引,当InnoDB引擎监视到某个二级索引在频繁的使用时,经常访问的二级索引数据会自动被生成到hash索引里面去(最近连续被访问三次的数据),自适应哈希索引通过缓冲池的B+树构造而来,因此建立的速度很快。

索引按是否为主键分类

索引按是否为主键分类分为主键索引和辅助索引。辅助索引又可分为唯一性索引、普通索引、前缀索引等。

主(键)索引

主索引也就做主键索引,是建立在主键列上的索引。一张数据表有只能有一个主键,并且主键不能为null不能重复。InnoDB中聚集索引默认就是建立在主键上,此时主索引就是聚集索引。但这两者并不完全等同,例如MyISAM也会为表的主键创建主键索引,但MyISAM不支持聚集索引,此时建立的主索引是非聚集索引。当没有显示的指定表的主键时,InnoDB会自动先检查表中是否有唯一索引的字段,如果有,则选择第一个唯一索引的字段为默认的主键,否则InnoDB将会自动创建一个自增主键。

辅助索引

辅助索引又叫做二级索引,辅助索引是相对于主索引而言,辅助索引的叶子结点中存放的不是完整的数据记录,而是主键,当辅助索引不是覆盖索引时(下面有对覆盖索引的介绍,读者可以滑动到下面先了解覆盖索引),我们通过辅助索引找到记录的主键或者行号(MyISAM中存放的是行号,InnoDB中是主键),再通过主键在聚集索引中进行查找。助索引又可分为唯一性索引、普通索引、前缀索引等类。

唯一索引

唯一索引的属性列不能出现重复的数据,但是允许数据为NULL,一张表允许创建多个唯一索引。建立唯一索引的目的大部分时候都是为了保证该属性列的数据唯一性。

普通索引

除了主键和唯一索引之外的索引都可以称作普通索引,是用来加快查找速度的。

前缀索引

前缀索引只适用于字符串类型的数据。前缀索引是对文本的前几个字符创建索引,相比普通索引建立的数据更小, 因为只取前几个字符。

索引按存储结构分类

聚集索引

聚集索引-数据存储的物理顺序与聚集索引值的逻辑顺序相同(查询效率快的原因),一个表中只能拥有一个聚集索引,一般默认是主键。例如InnoDB中,使用的就是聚集索引,默认聚集索引建立在主键上,所以数据的物理存储顺序其实就是以主键值的大小顺序进行排序存储。例如数据表中已经插入主键值为1、3、5、7、9的数据(存储顺序以主键值大小顺序进行存储),此时我要插入主键值为4的数据记录,此时磁盘上数据的存储顺序就变成了1、3、4、5、7、9。这也是聚集索引修改慢的原因,插入数据可能造成数据的移动,需要对数据页进行重排序,开销很大,所以一般采取逻辑主键自增。

聚集索引的叶子结点就是对应的数据结点,也就是说叶子结点中存储了关键字所在的一行的完整用户记录。Innodb采用聚集索引,数据与索引聚集在一起,它们基本是等同的,Data域存的是数据本身。索引也是数据。数据和索引存在一个XX.IDB文件中,所以也叫聚集索引。

InnoDB的聚集索引默认是建立在主键之上,但如果没有主键被定义,那么该表的第一个唯一非空索引被作为聚集索引;如果没有主键也没有合适的唯一索引,那么innodb内部会生成一个隐藏的主键作为聚集索引,这个隐藏的主键是一个6个字节的列,改列的值会随着数据的插入自增。

在这里插入图片描述

非聚集索引

非聚集索引中索引值的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引。数据是以聚集索引值的顺序进行存储,但聚集索引只在搜索条件是主键的时候才起作用,因此我们常常使用到非聚集索引,那么如何使用呢?我们需要以非聚集索引值建立一颗新的B+树,比如主键为C1,我们经常以字段C2为条件进行查找,那可以在C2上建立一个非聚集索引,以C2值为关键字建立一棵B+树。当以C2为条件进行查找时,就以C2值 在该B+树上进查找,查找到后,若需要select的字段存在叶结点中,则返回该值,若不在,则需要进行回表操作。
(InnoDB回表操作-InnoDB中叶子结点除了存储了该记录的关键字,还存储了主键值,通过主键值在聚集索引中查找到该具体记录。)
(MyISAM回表操作-MyISAM中叶子结点除了存储该记录的关键字,还存储了行号,通过行号去查找具体记录。)

非聚集索引的叶子层并不和实际数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针方式。非聚集索引层次多,不会造成数据重排序。( MyISAM使用非聚集索引,Data域中存的是数据地址。索引是索引,数据是数据。索引放在XX.MYI文件中,数据放在XX.MYD文件中,所以也叫非聚集索引。
在这里插入图片描述

聚集索引和非聚集索引小结

聚集索引和非聚集索引的主要区别在于存储结构的不同,是数据和索引是一起存储,还是分开存储。聚集索引是把完整记录的部分数据当作索引,换句话来说聚集索引就是建立完整数据记录之上。而非聚集索引是与完整数据记录分开存放。因此我们在非聚集索引中要查找的字段不止索引包含的字段,就需要拿着主键或者行号去完整数据记录存放的地方进行记录查找。

索引按索引列数分类

建立在一列上面的索引是单列索引,建立在多列上面的索引是联合索引。

联合索引

联合索引指的是以多个列的大小作为排序规则,同时在多个列上建立索引。例如为A1、A2两个字段建立联合索引,在建立B+树的过程中,我们以A1的大小顺序进行树的构建,若A1相同时,则以A2的大小为顺序进行树的构建。且目录数据页表中每条目录项记录都由A1、A2、页号这三个部分组成,各条记录先按照A1列的值进行排序,如果记录的A1列相同,则按照A2列的值进行排序。叶子结点(用户记录数据表)记录了A1、A2、主键值。(当查找的字段不止A1、A2、主键值时,需要通过主键值去查聚集索引的B+树来获得完整用户记录)
在这里插入图片描述
最左匹配原则: 在使用联合索引时,我们要注意最左匹配原则。当查询条件和ORDER BY子句不满足最左匹配原则时,索引未命中,进行index等级的索引扫描。最左匹配原则也叫最左前缀原则,如果查询的时候查询条件精确匹配索引的左边连续一列或几列,则索引命中。但索引进行从左往右进行匹配时,只能匹配值而不能匹配范围,当遇到范围查询(>、<、between、like左匹配)等就不能进一步匹配了,后续退化为线性查找。因此我们建立索引时,应将经常做范围查询的字段放在索引的后面。

例如,建立联合索引(name,age,high,weight),表中字段不止这四个

select * from user where name=xx and age=xx ; //可以命中索引,需要回表
select * from user where name=xx ;           / / 可以命中索引,需要回表
select * from user where age=xx and name=xx ; //可以命中索引,需要回表
select * from user where age=xx ;           / / 无法命中索引,index等级索引扫描  
select * from user where name=xx and age=xx and weight>10 and high=173 ;                                 / /命中索引,需要回表
select * from user where  age=xx and name=xx and weight=10 and high<173   / /索引命中age name,high,后续进行线性查找
select * from user where  age=xx and name=xx and weight>10 and high<173    / /索引命中age name,high,后续进行线性查找      

注意: 上例中第三行查询虽然看起来不满足最左匹配原则,但它具有索引的所有字段,只是顺序不同而已,查询引擎会对其优化,调整顺序,使得索引命中。
注意: 仔细观察最后三行查询的区别,倒数第三行之所以能命中索引,是因为查询引擎会自动优化查询的条件顺序,以匹配更多的索引字段。第一行被优化为name=xx and age=xx and high=173 and weight>10 的查询顺序,因此查询匹配。倒数第一行第二行都是因为索引的第三个字段是范围查询,即使是优化之后,索引从左向右进行字段匹配,到了第三个字段high就停止匹配,因此只命中了age、name、high三个字段,后续字段进行线性查询。

其它类别的索引分类

覆盖索引(尽量使用)

如果一个索引包含了所有需要查询的字段的值,我们就称之为“覆盖索引”。这种索引避免了进行回表操作。比如我们在字段username和high上创建联合索引。

select username , age from user where username = 'Java' and high=173
C

当执行以上sql语句时,这个联合索引其实就是个覆盖索引,不需要进行回表操作

冗余索引

冗余索引指的是多个索引的前缀列相同,或者在联合索引中包含了主键的索引。例如一张表有索引(name)和索引(name,age)或者索引(name,age,high)三个索引,这三个索引就是冗余索引。能命中(name,age,high)索引的查询肯定能命中索引(name)和索引(name,age)。我们需要避免冗余索引,当我们需要通过构建覆盖索引时,最好是在已有的索引上面扩展,而不是新建索引。例如上例子中要用到索引(name,age)来避免回表操作,我们就通过在索引(name)上面进行扩展,加入age字段作为索引的一部分。

重复索引(避免使用)

重复索引指的是在同一个列或者顺序相同的几个列(age,school),建立了多个索引,重复索引没有任何帮助只会增大索引文件,影响更新速度。

MyISAM中的索引方案

MyISAM存储引擎虽然默认使用的也是 B+索引,但它使用的是非聚集索引,数据和索引是分开的,索引放在XX.MYI文件中,数据放在XX.MYD文件中。MyISAM的表中数据是按照插入先后顺序进行存储的,不是以主键值的大小顺序进行存储的。但每一个记录都有一个行号,我们可以通过行号在数据文件中找到完整用户记录。MyISAM会为表的主键创建B+索引,数据页的每个记录中不仅有主键值还有行号,通过主键值获得行号,然后进行回表操作,用行号去数据文件中进行完整记录的查找。
在这里插入图片描述

发布了20 篇原创文章 · 获赞 27 · 访问量 2649

猜你喜欢

转载自blog.csdn.net/qq_41008202/article/details/105301413