Mysql 是一款非常受欢迎的数据库产品,在开发过程中,我们总是希望可以拥有更快的查询速度。添加索引是经常使用的优化,以我们最常使用的 Innodb 和 Myisam 存储引擎为例,我们在创建索引时,提供了 B-Tree 和 Hash 两种索引类型,多数情况我们都会选择 B-Tree 类型的,它也是默认的索引类型。接下来介绍一下 B-Tree 和 Hash 两种索引类型,以及该如何进行选择。
B-Tree 索引
B-Tree 索引使用 B-Tree 数据结构来存储数据,在 Mysql 数据库中,多数的存储引擎都支持该类型。存储引擎以不同的方式使用 B-Tree 索引,性能也各有不同,各有优劣。Myisam 使用前缀压缩技术使得索引更小,并且通过数据的物理位置引用被索引的行。Innodb 则按照原数据格式进行存储,根据主键引用被索引的行。
B-Tree 通常意味着所有的值都是按顺序进行排列的,并且每一个叶子页到根的距离相同。B-Tree 索引能够加快数据的访问速度,因为存储引擎不再需要扫描全表来获取需要的数据,取而代之的是从索引的根节点开始进行搜索。根节点存放了指向子节点的指针,存储引擎根据这些指针向下查找。最终存储引擎要么是找到对应的值,要么是该值不存在。叶子节点的指针指向被索引的数据,树的深度和表的大小直接相关。
由于 B-Tree 对索引列是顺序存储的,所以很适合查找范围数据。B-Tree 索引适用于全键值、键值范围或键前缀查找,其中键前缀只适合根据最左前缀的查找。总结一下 B-Tree 索引适合的查询有:
- 全值匹配查询,即和索引中的所有列进行匹配;
- 前缀查找,即可以匹配某一列的开头部分,例如我们使用的模糊查询 ( like xx% )
- 范围查询
- 顺序查找,因为索引树中的节点是有序的,所以除了按值查找之外,索引还可以用于排序操作。一般来说,如果 B-Tree 可以按照某种方式查找到值,那么也可以按照这种方式进行排序。所以,如果 ORDER BY 子句满足前面的几种查询类型,则这个索引也可以满足对应的排序需求。
当然 B-Tree 索引也有自己的限制,例如:
- 如果不是按照索引的最左列开始查找,则无法使用索引,比如 like %xx,就无法使用到索引;
- 不能跳过索引中的列;
- 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找。
Hash 索引
哈希索引基于哈希表实现,只有精准匹配索引所有列的查询才有效。对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码,哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行中的指针。因为索引只需要存储对应的哈希值,所以索引的结构十分紧凑,这也让哈希索引查找的速度非常快。当然也有一些不足点:
- 哈希索引值包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。但是访问内存中的行的速度很快,所以多数情况下对于性能影响不大;
- 哈希索引数据不是按找索引值顺序存储的,所以无法用于排序;
- 哈希索引也不支持部分索引列匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值的;
- 哈希索引只支持等值的比较查询,包括 =、IN()、<=>,也不支持任何范围查询;
- 容易产生哈希冲突;
由于哈希索引的这些限制,哈希索引只适用于特定的场合,如何适合使用哈希索引,它带来的性能提升将是非常明显的。
根据对于 B-Tree 和 Hash 索引的介绍,由于 B-tree 索引的限制更少,所以我们多数会选择它来创建索引,适合于多数的业务场景。不过 InnoDB 存储引擎有一个特殊的功能叫做"自适应哈希索引",当 Innodb 注意到某些索引值被使用的非常频繁时,它会在内存中基于 B-Tree 索引值上再创建一个哈希索引,这样就让 B-Tree索引也具有哈希索引的一些优点,例如如快速查找。
以上为 B-Tree 和 Hash 索引的介绍和用途,具体还是要根据业务场景进行选择,让项目能够更稳定快速的运行。
文章同步发布在我的个人博客中,传送门Hesunfly Blog
网友评论