MySQL复合索引中的键的高性能排序(WRT Rails多态关联和STI)

以前,我在ActiveRecord中询问了关于多态外键的复合索引的问题 。 我的问题的基础是我的理解,索引应该基于列的基数,并且在Rails的STI类型和多态_type列上通常具有相当低的基数。

接受我的问题的答案是正确的 – 将高基数_id列和低基数_type列编入索引是有价值的,因为它们一起具有高基数 – 我的下一个问题是:你应该如何订购你的化合物索引?

[owner_id,owner_type]的索引首先放置具有较高基数的字段,而[owner_type,owner_id]将具有较高基数的字段放置在第二位。 使用前一个键的查询是否比使用后一个键的查询更高效,或者它们是否同样高效?

我问,因为这对我如何为服务STI模型的表订购复合键有特别的影响。 STI Rails查找器几乎总是查询类型列 – 这也是一个通常低基数的列。 因此,比其他索引更频繁地查询类型列。 如果更频繁地查询类型列,那么使用类型前导索引可能是有意义的,因为较少特定的查询可以利用索引的第一部分来产生性能提升。 但是,对于高度特定的查询而言,我不会因为性能的损害而小费。 利用索引的高基数部分。

根据我自己的研究(但我不是DBA专家),我了解到在决定复合键索引的顺序时需要考虑两件事。

首先,关于列的基数,索引通常更好地搜索具有高基数的列。 所以我倾向于在索引中首先放置具有最高基数的列。 作为参考,有一篇题为“ MySQL查询优化 ”的文章说:

索引最适用于具有相对于表中行数的高基数的列(即,具有许多唯一值和少量重复项的列)。

在您的情况下, _id列显然更适合该定义,因此它们更适合作为键的前缀。

另一件需要考虑的事情是这些索引的可重用性。 大多数(如果不是全部)数据库系统允许重用复合键的前缀。 例如, (owner_id, owner_type)上的复合键也可以由owner_id上的查询使用,但不能在owner_typeowner_type

因此,根据您在问题中的解释,使用两个索引可能会更好: (owner_id, owner_type)上的复合键索引和(owner_type)上的另一个(owner_type)

最后,它真的归结为您的数据集和查询。 尝试使用不同复合键排序的多个场景,基准测试,以了解什么是最佳解决方案。 另外,不要忘记索引会对表造成写入惩罚。

更新 :还有一个关于复合键索引的另一个相当流行的SO问题:

我什么时候应该使用复合索引?

TL; DR首先输入类型,然后输入id。

确实,将id放在第一位会增加第一个决策的基数,从而可以轻松扫描结果记录或应用第二个小索引。 但是,如果您单独按类型查询(您将使用),则必须在类型上维护另一个顶级索引,这将使您在写入时获得性能影响。

反过来, [type, id]将提供一个顶级索引,只需按类型搜索即可重复使用。 第二个决定将始终对应于单个行,因为id按类型是唯一的,因此在索引解析后仍然可以确保没有行扫描。

IMO维持另一个索引的写入性能不值得首先不采用类型决策树的边际收益。