索引
常见索引
全文索引
将储存在数据库中的大段文本数据(文章等)中任意的内容信息查询出来的技术。
倒排索引
全文索引通常使用倒排索引实现。
它在辅助表中储存了单词与单词自身在一个或多个文档中所在位置之间的映射。这种关联通常使用关联数组实现,拥有两种表现形式:
- inverted file index
- full inverted index
InnoDB中的实现
采用了full inverted index的实现方式。
哈希索引
哈希表是一种以键-值(key-value)存储数据的结构,我们只要输入待查找的值即key,就可以找到其对应的值即Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后把value放在数组的这个位置。
数据库中一般采用最简单的碰撞解决技术 链接法
即将发生碰撞的元素都连接在一个链表上
哈希函数最好能尽量避免碰撞的产生 数据库一般采用除法散列的方法
使用场景
-
等值查询的场景
-
有序数组索引只适用于静态存储引擎
自适应哈希索引
由InnoDB自主控制、实现的哈希索引
基于缓存池内的数据库构建
根据访问频率和模式自动的为某些热点页构建哈希索引。
InnoDB中的哈希索引
InnoDB中使用哈希算法对字典进行查找,其冲突机制采用链表方式,哈希函数使用除法散列方式,
B+树索引
以2-3树为基础的实现的多元素节点多叉树,且在叶子节点储存数据,并用双向链表将叶子节点连接。
聚簇索引
B+树本身就是一个目录,或者说本身就是一个索引。它有两个特点:
-
使用记录主键值的大小进行记录和页的排序,这包括三个方面的含义:
- 页内的记录是按照主键的大小顺序排成一个单向链表。
- 各个存放用户记录的页也是根据页中用户记录的主键大小顺序排成一个双向链表。
- 存放目录项记录的页分为不同的层次,在同一层次中的页也是根据页中目录项记录的主键大小顺序排成一个双向链表。
-
B+树的叶子节点存储的是完整的用户记录。所谓完整的用户记录,就是指这个记录中存储了所有列的值(包括隐藏列)。
我们把具有这两种特性的B+树称为聚簇索引,所有完整的用户记录都存放在这个聚簇索引的叶子节点处。这种聚簇索引并不需要我们在MySQL语句中显式的使用INDEX语句去创建(后边会介绍索引相关的语句),InnoDB存储引擎会自动的为我们创建聚簇索引。另外有趣的一点是,在InnoDB存储引擎中,聚簇索引就是数据的存储方式(所有的用户记录都存储在了叶子节点),也就是所谓的索引即数据,数据即索引。
辅助索引
在最终叶节点中储存的是主键值,即通过辅助索引查询还需要回表,拿主键值再在聚簇索引中查询。
联合索引
覆盖索引
仍然是B+树结构,但通过在辅助索引中通过维护冗余的数据,满足查询需求。就不用再进行回表。
最左匹配原则
MySQL会一直向右匹配直到遇到范围查询(>,<,BETWEEN,LIKE)就停止匹配。因为B+树的数据页和记录先是按照左边列的值排序的,在左边列的值相同的情况下才使用,右边列进行排序,也就是说左边列的值不同的记录中右边的值可能是无序的。
索引下推
MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。
作用
优化单表访问
直接使用全表扫描的方式执行查询要遍历好多记录,开销太大。如果查询语句中的搜索条件可以使用到某个索引,那直接使用索引来执行查询可能会加快查询执行的时间。
- 使用索引进行查询
- 针对主键或唯一二级索引的等值查询
- 针对普通二级索引的等值查询
- 针对索引列的范围查询
- 直接扫描整个索引
代价
-
空间上的代价
这个是显而易见的,每建立一个索引都要为它建立一棵
B+树,每一棵B+树的每一个节点都是一个数据页,一个页默认会占用16KB的存储空间,一棵很大的B+树由许多数据页组成,那可是很大的一片存储空间呢。 -
时间上的代价
每次对表中的数据进行增、删、改操作时,都需要去修改各个
B+树索引。而且我们讲过,B+树每层节点都是按照索引列的值从小到大的顺序排序而组成了双向链表。不论是叶子节点中的记录,还是内节点中的记录(也就是不论是用户记录还是目录项记录)都是按照索引列的值从小到大的顺序而形成了一个单向链表。而增、删、改操作可能会对节点和记录的排序造成破坏,所以存储引擎需要额外的时间进行一些记录移位,页面分裂、页面回收啥的操作来维护好节点和记录的排序。
索引的选择和使用
选择
只为用于搜索、排序或分组的列创建索引
也就是说,只为出现在WHERE子句中的列、连接子句中的连接列,或者出现在ORDER BY或GROUP BY子句中的列创建索引。
考虑重复数据
索引列的类型尽量小
使用字符前缀建立索引
减少空间占用,但失去了排序的特性
全值匹配
如果我们的搜索条件中的列和索引列一致的话,这种情况就称为全值匹配
搜索条件的顺序不会影响,优化器会帮忙调整
匹配最左边的值
如果想使用联合索引中尽可能多的列,搜索条件中的各个列必须是联合索引中从最左边连续的列。
匹配列前缀
在字符串的排序中也是按从左到右进行排序的,因此使用前缀进行匹配也可以使用索引。但后缀不行,原因同最左匹配原则
排序
B+树索引的建立本身就是对某列数据进行排序