索引是在存储引擎层实现的,而不是服务层。
1. B-Tree索引
当人们谈及索引而没有说明其类型的时候,多半是指B-Tree索引,它通常使用B-Tree数据结构来保存数据。
存储引擎使用了不同的方式把索引保存到磁盘上,它们会影响性能。例如,MyISAM使用前缀压缩以减小索引,而InnoDB不会压缩索引,因为它不能把压缩索引用于某些优化。同样,MyISAM索引按照行存储的物理位置引用被索引的行,但是InnoDB按照主键值引用行。
B-Tree通常意味着数据存储是有序的,并且每个叶子页到根的距离是一样的。根节点和叶子之间可能有很多层节点页面。树的深度取决于表的大小。
B-Tree索引加速了数据访问,因为存储引擎不会扫描整个表得到需要的数据。相反,它从根节点开始。根节点保存了指向子节点的指针,并且存储引擎会根据指针寻找数据。它通过查找节点页中的值找到正确的指针,节点页包含子节点中值的上界和下界。最后,存储引擎可能无法找到需要的数据,也可能成功德找到包含数据的叶子页面。
B-Tree索引能很好地用于全键值、键值范围或键前缀查找。它们只有在查找使用了索引的最左前缀的时候才有用。
能使用B-Tree索引的查询类型:
匹配全名。
匹配最左前缀。
匹配列前缀。
匹配范围值。
精确匹配一部分不且匹配某个范围中的另一部分。
只访问索引的查询:B-Tree索引通常能支持只访问索引的查询,它不会访问数据行。(覆盖索引)
下面是B-Tree索引的一些局限:
如果查找没有从索引列的最左边开始,它就没什么用处。
不能跳过索引中的列。
存储引擎不能优化访问任何在第一个范围条件右边的列。
所以索引的列顺序极端重要。这些局限和列顺序有关。
2.哈希索引
哈希索引建立在哈希表的基础上,它只对使用了索引中的每一列的精确查找有用。对于每一行,存储引擎计算出了被索引列的哈希码,它是一个较小的值,并且有可能和其他行的哈希码不同。它把哈希码保存在索引中,并且保存了一个指向哈希表中每一行的指针。
在MySQL中,只有Memory存储引擎支持显式的哈希索引。
因为索引本身只保存简短的哈希值,哈希索引显得非常紧凑。哈希值的长度不会依赖于索引的列。TINYINT列的哈希索引和大型字符列的哈希索引大小事一样的。
这样来看,查找的速度是很快的。然而,哈希索引有一些局限:
因为索引只包含了哈希码和行指针,而不是值本身,MySql不能使用索引中的值来避免读取行。幸运的是,访问内存中的行很快,因此这通常不会降低性能。
MySQL不能使用哈希索引进行排序,因为它们不会按序保存行。
哈希索引不支持部分键匹配。
哈希索引只支持使用了=,IN()和<=>的相等比较。它不能加快范围查询,例如WHERE price>100
访问哈希索引中的数据非常快,除非碰撞率很高。当发生碰撞的时候,存储引擎必须访问链表中的每一行指针,然后逐行进行数据比较,以确定正确的数据。
如果有很多碰撞,一些索引维护操作就有可能会变慢。如果在一个选择性很低(很多碰撞值)的列上创建哈希索引,然后从表中删除一行,那么从索引中找到行的代价会很高。
这些限制使哈希索引只在特殊情况下有用。然后,当它符合应用程序需要的时候,就能极大地改善性能。一个例子就是数据仓库应用程序,其中经典的“星形”架构要对查找表进行很多联接操作。哈希所用正是查找表所需要的。
InnoDB存储引擎有一个特别的功能,叫自适应哈希索引。当InnoDB注意到一些索引值被很频繁地访问的时候,它就会在B-Tree的顶端为这些值建立起内存中的索引。这使B-Tree索引有了一些哈希索引的特性。这个过程是全自动的,既不能控制,也不能配置它。
如果存储引擎不支持哈希索引,就可以按照InnoDB使用的方式模拟自己的哈希索引。
想法非常简单:在标准B——Tree索引上创建一个伪哈希索引。它和真正的哈希索引不是一回事,因为它还是使用B-Tree索引进行查找。然而,它将会使用键的哈希值进行查找,而不是键自身。你所要做的事情就是在WHERE子句中手动地定义哈希函数。(其实就是在表中加上一个列,这个列存储的是原来被索引的列的值的哈希值,在选择时因为MYSQL查询优化器注意到这个存储哈希值的列很有选择性,就会使用里面的值进行索引查找)
3. 空间索引(R-Tree)
MyISAM支持空间索引,它可以使用诸如GEOMETRY这样的地理空间数据类型。
4. 全文索引
FULLTEXT是MyISAM表的一种特殊索引。它从文本中找到关键字,而不是直接和索引中的值进行比较。全文索引用于MATCH AGAINST操作,而不是普通的WHERE子句操作。