覆盖索引中的列顺序重要吗?

Ela*_*ina 3 mysql

我有以下覆盖索引:

INDEX (col1, col3); -- index 1
INDEX (col1, col2, col3); -- index 2
Run Code Online (Sandbox Code Playgroud)

因为我想支持以下类型的查询:

1)

  SELECT col3
    FROM my_table
   WHERE col1 = ... AND
         col2 = ...
ORDER BY col3
Run Code Online (Sandbox Code Playgroud)

2)

  SELECT col3
    FROM my_table
   WHERE col1 = ... 
ORDER BY col3
Run Code Online (Sandbox Code Playgroud)

我不熟悉覆盖索引的工作原理。索引1是多余的吗?或者覆盖索引是否要求列并排?

Ric*_*mes 5

“覆盖”这个词一开始就是错误的。我稍后会回到这个话题。

查询的最佳索引可以总结为:

  • 索引中的第一列必须是 , 以 -any_ 顺序排列的所有=WHERE
  • 索引中的最后一列必须是ORDER BY相同顺序的列并且可以是 allASC或 all DESC。(MySQL 8.0 这里有一个例外。)

您的索引 1 对于查询 2 来说是必要且充分的。
您的索引 2 对于查询 1 来说是必要且充分的。
任何不同的情况都将是次优的。

请注意,它们也将是“覆盖”的,因为其中任何位置的所有列都SELECT可以在相应的索引中找到。

索引 2“覆盖”了两个查询,但对于查询 2 来说并不是很好。

  1. 为每个重要查询设计最佳索引。
  2. 消除冗余。示例:给定INDEX(a), INDEX(a,b),丢弃前者。
  3. 然后考虑在末尾添加一些列来使索引“覆盖”。

有关这些提示以及更多信息,请参阅http://mysql.rjweb.org/doc.php/index_cookbook_mysql

这是“覆盖”,但效率不高,因为col99在索引中第一个,但不用于过滤或排序:

INDEX(col99, col1, col2, col3)
Run Code Online (Sandbox Code Playgroud)

它可能会被使用,但只是因为它具有覆盖性。它不能用于过滤或排序。

这是“覆盖”,用于避免排序,因为ORDER BY列在前面:

INDEX(col3, col2, col1)
Run Code Online (Sandbox Code Playgroud)

无论各个列的基数如何,查询 1 都会对此感到满意:

INDEX(col2, col1, col3)
Run Code Online (Sandbox Code Playgroud)

回到标题问题:

覆盖索引中的列顺序重要吗?

回答:

  • 为了“掩盖”:不。
  • 为了加快查询速度:这取决于。这就是为什么我建议从其他“规则”开始构建良好的索引。

打个比方

  • 表是一组无序的事物。模拟:教科书。
  • 索引是一个有序列表,引用那些东西。类比:课本后面的索引。
  • 当回答问题所需的所有内容都位于索引中(并且您不需要翻阅教科书正文)时,索引就是“覆盖”。

B+树有两个重要的属性:

  • 在任何特定单词处都可以快速跳到中间。
  • 从该单词向前扫描速度很快。