首页 > 解决方案 > MySQL Btrees:当使用所有列时,基数和列顺序对复合索引是否重要?

问题描述

我很难弄清楚,所以让我问你。给定以下查询:

select name from users where company_id = ? and creation_date > ?

假设我们只有 2 家公司,每家公司都有数百万用户在不同的时刻创建。所以基数creation_date要高得多。以下哪个索引更快,为什么?

  1. index_a(公司 ID,创建日期)
  2. index_b(创建日期,公司 ID)
  3. index_c(创建日期)
  4. index_d(company_id)

哪个指数更快(或理论上相等)?忽略磁盘空间使用,除非这会以某种方式影响读取性能。我的想法:

(index_b ~= index_c) > index_a > index_d因为在 Btree 中,“时间戳”将被分组在一个区域中,因此提取会更早停止。实际上并不重要,company_id因为数据库需要使用索引中的 ROWID 来触摸表行以name获取SELECT. 几乎没有区别。排在第二位index_a的是在 BTREE 中将低基数值“组合”在一起,因此“b-search”需要一些时间通过限制搜索范围来显示其值creation_date(在指数)。最后index_d,由于明显的原因(基数为百万行中的 2),情况更糟。

额外问题:如果我们有 10kk 行,公司 A 和公司 B 有 5kk 行,两家公司平均分配 7kk 时间戳,而其他 3kk 完全不同的时间戳怎么办。7kk 范围内的搜索会比 3kk 范围内的搜索差得多吗?

那正确吗?我错过了什么?

(可视化算法的好地方:https ://www.cs.usfca.edu/~galles/visualization/BTree.html )

PS: StackOverflow 中有两个相互矛盾的答案:

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

对于不同基数列的复合索引,顺序重要吗?

标签: mysqldatabasealgorithmindexingb-tree

解决方案


对于该特定查询, index_a 应该是最快的,因为结果与索引中的范围完全对应。

使用 index_b 或 index_c 比较慢。您必须获取有效日期的范围,然后过滤掉公司 ID 错误的行。在这两者中, index_c 较慢,因为您必须触摸过滤掉的行。

使用 index_d 是最慢的。您可以找到公司 ID 的范围,但必须扫描所有行以查找匹配日期。


推荐阅读