【六】高性能MySql笔记——高性能索引类型基础
数据库优化除了好的设计,还需要好的索引,而作者在工作中与团队成员、同事、以及在面试新人的时候发现,很多朋友并没有对索引有一个正确的认识。当问到如何优化数据库时?得到的答案,也是大家所能想到的唯一答案就是建立索引。但当我问到如何正确建立索引时,却都不能正确回答。我曾经在团队项目中实际测试过一个不恰当的索引会导致效率慢一个数量级。所以我们有必要真正的去了解一下索引的原理。
索引:保存在内存中,存储引擎用于快速找到记录的一种数据结构。索引优化应该是对查询性能优化最有效的手段了。索引能够轻易将查询性能提高几个数量级“最优”的索引有时比一个“好的”索引性能要好两个数量级。在MySql中一个查询会先在索引中找到对应的值,然后根据匹配的索引记录找到对应的数据行。
基础
索引可以包含一个或多个列的值。MySql只能高效地使用索引的最左前缀列。创建一个包含两个列的索引,和创建两个只包含一个列的索引是大不相同的。无论是多么复杂的ORM工具,在精妙和复杂的索引面前都是“浮云”。
索引的类型
在MySql中,索引是在存储引擎层实现的。所以不同的存储引擎索引标准不通。索引根据CREATE TABLE语句定义索引时列的顺序。
B-Tree 索引
实际上很多存储引擎使用的是B+Tree索引,即每个叶子节点都包含指向下一个叶子节点的指针,从而方便叶子节点的范围遍历。B-Tree通常意味着所有的值都是按顺序存储的,并且每一个叶子页到根的距离相同。B-Tree 索引不再需要全表扫描来获取需要的数据,取而代之的是从索引的根节点开始进行搜索。根节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下层查找。通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点页中值的上限和下限。最终存储引擎要么是找到对应的值,要么该记录不存在。叶子节点比较特别,他们的指针指向的是被索引的数据,而不是其他的节点页。这种查找类似与算法中的二分法。(下图引自:https://blog.csdn.net/sdauzxl/article/details/52234482)。
B-Tree索引适用于全键值,键值范围或键前缀查找。索引的另一个作用是对数据进行ORDER BY操作。在优化性能的时候,可能需要使用相同的列但顺序不同的索引来满足不通的查询需求。
B-Tree索引的限制
①如果不是按照最左前缀的顺序无法使用索引;
②同样也不能跳过索引中的列;
③在查询中某个列是范围查询,那么其右边的所有索引都将不能使用。
哈希索引
哈希索引是基于哈希表实现,只有精确匹配索引所有列的查询才有效。Memory引擎支持此索引。因为哈希值并不能保证绝对唯一性,所以Memory引擎支持非唯一哈希索引。即如果有多条数据具有相同的哈希值,那么会同时返回。哈希索引结构紧凑,所以具有非常快的查询速度。Memory引擎也支持B-Tree索引。
哈希索引的限制
①哈希索引不能避免读取行;
②哈希索引是无序的,所以无法进行排序;
③哈希索引不支持部分索引列查找;
④哈希索引只支持等值比较查询,不支持范围查询;
⑤访问哈希索引的数据非常快,除非有很多哈希冲突。当出现哈希冲突时,存储引擎必须进行全表扫描;
⑥哈希冲突很多的话,索引维护代价会很高。
InnoDB存储引擎本身不具备哈希索引能力,但是其具有类似的“自适应哈希索引”。当某些索引使用频繁时,InnoDB会自动在B-Tree索引之上再创建一个哈希索引。这个能力不需要我们维护。对于其他一些不支持哈希索引的存储引擎我们可以创建自定义哈希索引。这种操作需要我们在表中增加一列保存对应列的哈希值,然后在WHERE子句中手动指定使用哈希函数。
SELECT id FROM url WHERE url="http://www.codertoy.com" AND url_crc = CRC32("http://www.codertoy.com");
在使用哈希索引时,尽量不要使用SHA1()和MD5()作为哈希值。因为其值长,且比较慢。对于大数据量的数据表,可以考虑自己实现一个64位的哈希函数来避免出现大量的哈希冲突。
空间数据索引
空间数据索引无需前缀查询。空间索引会从所有维度来索引数据。查询时可以使用任意组合。MyISAM引擎支持这种索引,必须使用GIS相关函数MBRCONTAINS()等来维护数据。
全文索引
全文索引通过查找文本中的关键词,而不是直接比较索引中的值。这种索引类似于搜索引擎,不是简单的WHERE条件匹配。适用于MATCH AGAINST操作。
分形树索引
分形树索引具有B-Tree的很多优点,避免了B-Tree的很多缺点。
索引的优点
①索引减少了扫描数据的量;
②帮助服务器避免排序和临时表(B-Tree索引是顺序存储可支持ORDER BY和GROUP BY);
③索引可以将随机I/O变为顺序I/O,从而提高查询效率。