- 索引 (在 MySQL 中也叫作 “键(key)”) 是存储引擎用于快速找到记录的一种数据结构
索引基础
索引可包含一个或多个列的值。如果索引包含多个列,那么列的顺序也十分重要,因为 MySQL 只能高效地使用索引的最左前缀列。创建一个包含两个列的索引,和创建两个只包含一列的索引是大不相同的
索引的类型
B-Tree
当人们谈论索引的时候,如果没有特别指明类型,多半说的是 B-Tree 索引,它使用 B-Tree 数据结构来存储数据。(实际上很多存储引擎使用的是 B+Tree,即每一个叶子节点都包含指向下一个叶子节点的指针,从而方便叶子节点的范围遍历 )
B-Tree 对索引列是顺序组织存储的,所以很适合查找范围数据
注意:索引对多个值进行排序的依据是 CREATE TABLE 语句中定义索引时列的顺序。看一下最后两个条目,两个人的姓和名都一样,则根据他们的出生日期来排列顺序
可以使用 B-Tree 索引的查询类型。B-Tree 索引适用于全键值、键值范围或键前缀查找。其中键前缀查找只适用于根据最左前缀的查找
B-Tree 索引的限制
1、如果不是按照索引的最左列开始查找,则无法使用索引。例如上面例子中的索引无法用于查找名字为 Bill 的人,也无法查找某个特定生日的人,因为这两列都不是最左数据。类似地,也无法查找姓氏以某个字母结尾的人
2、不能跳过索引中的列。也就是说,前面所述的索引无法用于查找姓为 Smith 并且在某个特定日期出生的人。如果不指定名 ( first_name ) ,则 MySQL 只能使用索引的第一列
3、如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找到这里读者应该明白,前面提到的索引列的顺序是多么重要:这些索引都和索引列的顺序有关。在优化性能的时候,可能需要使用相同的列但顺序不同的索引来满足不同类型的查询需求
哈希索引
- 哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才有效。对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码,哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针
在 MySQL 中,只有 Memory 引擎显式支持哈希索引。这也是 Memory 引擎表的默认索引类型,Memory 引擎同时支持 B-Tree 索引。值得一提的是,Memory 引擎是支持非唯一哈希索引的,这在数据库世界里面是比较与众不同的。如果多个列的哈希值相同,索引会以链表的方式存放多个记录指针到同一个哈希条目中 -
下面来看一个例子
假设有如下表
表中包含如下数据
假设索引使用假想的哈希函数 f(),它返回下面的值 (都是示例数据,非真实数据)
则哈希索引的数据结构如下
注意每个槽的编号是顺序的,但是数据行不是。现在,来看如下查询
MySQL 先计算 ‘Peter’ 的哈希值,并使用该值寻找对应的记录指针。因为 f('Peter') = 8784,所以 MySQL 在索引中查找 8784,可以找到指向第 3 行的指针,最后一步是比较第 3 行的值是否是 'Peter' ,才确保就是要查找的行。
因为索引自身只需存储对应的哈希值,所以索引的结构十分紧凑,这也让哈希索引查找的速度非常快。然而,哈希索引也有它的限制。
- 哈希索引限制
1、哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。不过,访问内存中的行的速度很快,所以大部分情况下这一点对性能的影响并不明显
2、哈希索引数据并不是按照索引值顺序存储的,所以也就无法用于排序
3、哈希索引也不支持部分索引列匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值的。例如,在数据列 (A,B) 上建立哈希索引,如果查询只有数据列 A,则无法使用该索引
4、哈希索引只支持等值比较查询,包括 =、IN() 也不支持任何范围查询,例如 where price > 100
5、访问哈希索引的数据非常快,除非有很多哈希冲突(不同的索引列值却有相同的哈希值)。当出现哈希冲突时,存储引擎必须遍历链表中所有的指针,逐行进行比较,直到找到所有符合条件的行
6、如果哈希冲突很多的话,一些索引维护操作的代价也会很高。例如,如果在某个选择性很低(哈希冲突很多)的列上建立哈希索引,那么当从表中删除一行时,存储引擎需要遍历对应哈希值的链表中的每一行,找到并删除对应行的引用,冲突越多,代价越大
空间数据索引
MyISAM 表支持空间索引,可以用作地理数据存储
空间索引会从所有维度来索引数据。查询时,可以有效地使用任意维度来组合查询
全文索引
全文索引是一种特殊类型的索引,它查找的是文本中的关键词,而不是直接比较索引中的值
全文搜索和其他几类索引的匹配方式完全不一样。它有许多需要注意的细节,如停用词、词干和复数、布尔搜索等。全文索引更类似于搜索引擎做的事情,而不是简单的 where 条件匹配
索引的优点
最常见的 B-Tree 索引,按照顺序存储数据,所以 MySQL 可以用来做 order by 和 group by 操作。因为数据是有序的,所以 B-Tree 也就会将相关的列值都存储在一起。最后,因为索引中存储了实际的列值,所以某些查询只使用索引就能够完成全部查询了。
据此特性,总结下来索引有如下三个优点
1、索引大大减少了服务器需要扫描的数据量
2、索引可以帮助服务器避免排序和临时表
3、索引可以将随机 I/O 变为顺序 I/O