在MYSQL中,索引是在引擎层中而不是服务器层实现的。所以并没有统一的索引标准:不同存储引擎的索引的工作方式并不一样,也不是所有的存储引擎
都支持所有类型的索引。即使多个存储引擎支持同一种类型的索引,其底层的实现也可能不同
(1)B-Tree索引
如果没有特别指明类型的话,那么就代指为B-Tree引擎,它使用B-Tree数据结构来存储数据、大多数MYSQL的引擎都支持这种索引。
Archive引擎是一个例外(Archive在5.1之后在开始支持单个自增列的索引)。
虽然都是B-Tree索引,但是存储引擎以不同的方式使用B-Tree索引,性能也各有不同,各有优劣。例如:MyISAM使用前缀压缩技术使得索引更小,
但是InnoDB则按照原数据格式进行存储。再如MyISAM索引通过数据的物理位置引用被索引的行,而InnoDB则根据主键引用被索引的列
B-Tree通常以为这所有的值都是按顺序存储的,并且每个叶子页到跟的距离相同。如下图(InnoDB中的索引工作,MYISAM使用的结构有所不同,但是基本思想类似)
B-Tree索引能够加快访问数据的速度,因为存储引擎不再需要进行全表扫描,只需要从索引的根节点开始进行搜索。根节点中的保存了指向子节点
的指针,存储引擎根据这些指针开始向下查找,通过比较节点页的值和要查找的值向下搜索。这些指针实际上定义了子节点页中值的上下限,最终引擎必定会找到想用的值,除非这个值不存在
叶子结点保存的是指向被索引数据的指针,而不是其他的节点页
B-Tree对索引列是顺序组织存储的,所以很适合查找范围数据。例如,在一个基于文本域的索引树上,按字母顺序传递连续的值进行查找是非常合适的,所以像“找出是有意以1-K开头的名字”这样的查找效率会非常高
B-Tree索引适用于全键值、键值范围或键前缀查找。其中键前缀查找只适用于根据最左前缀的查找。
(1)全值匹配:全值匹配真的是和索引中的所有列进行匹配
(2)匹配最左前缀:只使用索引的第一列
(3)匹配列前缀:只匹配某一列的值的开头部分
(4)匹配范围值:匹配区间内的权值(最好使用与索引的第一列)
(5)精确匹配某一列并范围匹配另外一列:第一列全匹配,第二列进行范围匹配
(6)只访问索引的查询:B-Tree通常可以支持“只访问索引的查询”,即查询只需要访问索引,而无需访问数据列。
因为索引树种的节点是有序的,所以除了按值查找之外,索引还可以用于查询中的order by操作。一般来说如果B-Tree可以按照某种方式查找到的值,那么也可以用按照这种方式用于排序。所以,如果Order by字句满足前面列出的集中查询类型,则这个索引也可以满足对应的排序需求
下列是一些关于B-Tree索引的限制
(1)如果不是按照索引的最左列进行查找,那么就无法使用索引
(2)不能跳过索引中的列。比如你建了一个关于A B C的索引,那么你如果要查询B,那么必须也要查A,不能跳过A去查B,或者说查AC,不查B
(3)如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找
通过以上大家应该都知道了索引列顺序的重要性:以上所说的限制都和索引列顺序有关。在优化性能的时候,可能需要使用相同的列但顺序不同的索引来满足不同类型的查询需求。
(2)哈希索引
哈希索引是基于哈希表实现的索引。只有精确匹配索引索引列的查询才有效。对于每一行数据,在存储引擎都会对索引列计算一个哈希码,哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每一个数据行的指针
在MYSQL中,只有Memory引擎显式支持哈希索引。这也是Memory引擎表的默认索引类型(memory引擎也支持B-Tree索引)
值得一提的是,Memory引擎支持的是非唯一哈希索引(如果多个列的哈希值相同,索引会以链表的方式存放多个记录指针到同一个哈希条目中)
下面来看一个栗子
create table testhash{
fname varchar(50) not null,
lname varchar(50) not null,
key using hash(fname)
}Engine=MEMORY;
表中数据如下
假设索引使用家乡的哈希函数F(),他返回下面的值:
则哈希索引的结构如下
注意每个槽的编号是顺序的,但是数据行不是
看如下查询
MYSQL会计算'Peter'的哈希值,并使用该值寻找对应的记录指针。因为f('Peter')=8784,所以MYSQL在索引中查找8784,可以找到指向第三行的指针,最后一部是比较第三行的值是否为'Peter',以确保就是要查找的行
因为索引自身秩序存储对应的的哈希值,所以索引的结构十分紧凑,这也让哈希索引查找的速度非常快。然而哈希索引也有他的限制
(1)哈希索只包含哈希值和行指针,而不存储字段值。所以不能使用索引中的值来避免读取航。不过访问内存中的行速度很快,所以大部分情况下这一点对性能的影响并不大
(2)哈希索引数据并不是按照索引顺序存储的,所以不能排序
(3)哈希索引也不支持部分索引匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值。比如使用了AB来建立哈希索引,但是你查询的只查询A,那么就无法使用该索引
(4)哈希索引支持等值比较查询,包括=、IN()、<=>(这个不是<>)。也不支持任何范围查询,比如where xxx>xxx
(5)访问哈希索引的数据非常快,除非有很多哈希冲突(不同的索引列值却又相同的哈希值)。当出现哈希冲突的时候,存储引擎会遍历链表中所有的行指针,逐行比较,直到找到所有符合条件的行
(6)如果哈希冲突很多的话,一些索引维护操作的代价也会很高:比如,如果在某个选择性很低(哈希冲突很多)的列上建立哈希索引,那么当中表中删除一行是,存储引擎就需要遍历对应哈希值的链表中的每一行,找到并删除对应行的引用,冲突越多,代价越大
因为这些限制,哈希索引只是用与某些特定的场合。而一旦适合哈希索引,则他所带来的性能提升是非常大的,比如数据仓库中的星型schema。
(3)空间数据索引(R-Tree)
MyISAM表支持空间数据索引,可以用作地理数据存储。和B-Tree索引不同,这类索引无须前缀查询。空间索引会从所有维度来索引数据。查询时,可以有效的使用任意维度来组合查询。必须使用MySQL的IGS相关函数在维护数据。MySQL的GIS支持并不完善,所以大部分不会使用这个特性
(4)全文索引
全文索引是一种特殊类型的索引,它查找的是文本中的关键词,而不是直接比较索引中的值。全文搜索和其他几类索引的匹配方式完全不一样。他有许多需要注意的细节,如停用词、词干和复数、布尔搜索等。全文索引更类似与搜索引擎做的事情,而不是简单的where条件匹配
在相同的列上同时创建全文索引和基于值的B-Tree索引不会用冲突,全文索引适用于match against操作,而不是普通的where