首页 > 技术文章 > MySQL索引

lzxin 2019-02-20 13:42 原文

索引的种类


普通索引

最基本的索引,没有任何限制。

唯一索引

索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。

主键索引

是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。建立主键时就自动生成了该索引。

组合索引

指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。遵循最左匹配原则。

全文索引

主要用来查找文本中的关键字,而不是直接与索引中的值相比较

 

 

索引的类型

 

FULLTEXT

即为全文索引,目前只有MyISAM引擎支持。目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。

HASH

由于HASH的唯一(几乎100%的唯一)及类似键值对的形式,很适合作为索引。HASH索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。

BTREE

要讲B+树,就要先讲讲B树的规则:

 

而B+树是B树变体,其定义基本与B树相同,除了:

非叶子节点的子树指针与关键字个数相同

非叶子节点的的子树指针P[i],指向关键字值(K[i],K[i+1])的子树

非叶子节点只用来索引,数据都保存在叶子节点中

所有叶子节点均有一个链指针指向下一个叶子节点

 

B+树如图所示:

 

 

RTREE

 RTREE在mysql很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。

 

使用HASH索引的缺点

 

(1)Hash 索引仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询。
由于 Hash 索引比较的是进行 Hash 运算之后的 Hash 值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证和Hash运算前完全一样。

(2)Hash 索引无法被用来避免数据的排序操作。
由于 Hash 索引中存放的是经过 Hash 计算之后的 Hash 值,而且Hash值的大小关系并不一定和 Hash 运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算;

(3)Hash 索引不能利用部分索引键查询。

对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一起计算 Hash 值,而不是单独计算 Hash 值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也无法被利用。
(4)Hash 索引在任何时候都不能避免表扫描。
前面已经知道,Hash 索引是将索引键通过 Hash 运算之后,将 Hash运算结果的 Hash 值和所对应的行指针信息存放于一个 Hash 表中,由于不同索引键存在相同 Hash 值,所以即使取满足某个 Hash 键值的数据的记录条数,也无法从 Hash 索引中直接完成查询,还是要通过访问表中的实际数据进行相应的比较,并得到相应的结果。
(5)Hash 索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高。
对于选择性比较低的索引键,如果创建 Hash 索引,那么将会存在大量记录指针信息存于同一个 Hash 值相关联。这样要定位某一条记录时就会非常麻烦,会浪费多次表数据的访问,而造成整体性能低下。

 

 

使用B+树索引的优点


(1)B+树的磁盘读写代价更低

b+树的非叶子节点只保存了关键字的数据,没有保存具体的信息,这样内存中一次性读取的关键字就更多,相对来说IO读写速度也就降低了

(2)B+树的查询效率更加稳定

由于内部节点并不是最终指向内容的节点,而只是叶子节点中关键字的索引,所以任何关键字必须从根节点到叶子节点,是稳定的

(3)B+树更有利于对数据库的扫描

b树提高了IO性能,但没有解决效率低下的问题,b+树只需要遍历叶子节点就能进行数据库常见的范围查询

 

 

联合索引的最左匹配原则

1、最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

2、=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式

 

我对最左匹配原则的理解为每个索引点都保存了联合索引项,以建立了(a,b,c)索引为例,会从左到右建立B+树,也就是说先从a进行查找,如果a是等值查找,找到a会继续从b进行查找,b如果也是等值查找,找到b后会继续从c进行查找,这样a,b,c都走到了索引。但是如果从a开始查找的时候,若a是范围查找,还是能依据索引进行查找,但根据最左匹配原则的第一条,会停止后面的匹配,也就是说查询去a的范围后,后面b的值和c的值都只能去a的范围中进行查询,走不了索引了。
下面就能很好理解为什么下面两个查询语句都能走索引了。
select * from test where a=10 and b =10 and c<10;
select * from test where a<10 and b <10 and c<10;

  

聚集索引和非聚集索引

MyISAM的索引是非聚集索引,具体表现在结构与数据的分离。MyISAM的B+树的叶子结点的data域中存储的是地址,与该地址相映射的是另一个文件中所存储的数据。因此需要从主键值获取到数据地址,再从地址获取具体数据。MyISAM的辅助索引与主键索引区别不大,只是主键索引的key不能重复。

InnoDB的索引是聚集索引,因为InnoDB的B+树的叶子结点的data域存储的就是数据,省去了根据地址查找数据的步骤。InnoDB的辅助索引的data域就是主键的数值,所以进行辅助索引前,会先获取主键的信息,所以主键不宜过大,因为会到致辅助索引过大,很消耗资源。InnoDB的主键是主键索引,非主键是辅助索引。

 

 

索引是建立越多越好吗? 


数据量小的表不需要建立索引,建立索引会增加额外的索引开销

数据变更需要维护索引,因此需要更多的索引意味着更多的维护成本

更多的索引意味着也需要更多的空间

 

 

索引的注意要点

 

1.列上进行函数计算将不会使用索引;
2.对于创建索引的列,避免存储NULL,NULL会使索引更加复杂、效率变低,可以使用NOT NULL进行约束;
3.对于模糊查询like '%abc%',将不会使用索引,而like 'abc%'将会使用索引;
4.对于not in、not exists、!=等负向查询将不会使用索引;
5.每次查询只使用一个索引,如果where条件使用了索引,order by将不再使用索引;
6.对于where子句中有多个查询条件的,单列索引的效率不如复合索引,因为查询每次只能使用一个索引;
7.MySQL只对以下操作符才使用索引:<、<=、=、>、>=、between、in,但是需要注意in的范围值不要太多;
8.union all可以使用索引,但本身效率不是很高,不建议使用;
9.列上进行类型转换的将不会使用索引;
10.老版本MySQL对OR条件不使用索引,新版本才支持,不建议使用OR。

 

参考:

https://www.cnblogs.com/luyucheng/p/6289714.html

https://www.cnblogs.com/yuan-shuai/p/3225417.html

 

推荐阅读