【问题标题】:MySQL INDEX join same table on different columnsMySQL INDEX 在不同列上连接同一张表
【发布时间】:2016-06-05 21:17:18
【问题描述】:

我的数据集的简化版本:

我有一张有两列 col1col2 的表格

我想优化这个查询:

SELECT * FROM mytable a
LEFT JOIN mytable b
ON a.col1 = b.col2

在此表上创建的最佳索引是什么?

  • 两个索引:col1 上的索引和col2 上的另一个索引
  • 一个双索引:两个索引col1,col2

让我们稍微复杂一点:(我的真实数据结构)

假设我的表中还有一列extract_date

SELECT * FROM mytable a
LEFT JOIN mytable b
ON a.col1 = b.col2 AND a.extract_date=b.extract_date

在此表上创建的最佳索引是什么?

  • 两个双索引:col1,extract_date 上的 index1 和 col2,extract_date 上的另一个索引
  • 一个三重索引:col1,col2,extract_date 上的索引

【问题讨论】:

  • 基本经验法则:在“决策上下文”中使用的任何字段:where 子句、order by、group by 等都应该被索引。您如何着手构建这些索引。
  • 我不同意...我看到有一些指导方针取决于数据集的粒度,以及 MySQL 是否决定使用它
  • 好吧,是的,如果它是一个 10 条记录的表,索引将是多余的。
  • 我说的是数百万行。粒度是指每列的不同值:col1 有 10 个不同的值,col2 有 1000 个不同的值
  • 那么索引在大多数情况下仍然会有所帮助。没有硬性/快速规则说“类型 X 和数量 Y 的索引将导致 Z% 的性能提升”。您必须以两种方式对其进行测试。如果您的特定数据集证明索引没有帮助,那么不要浪费创建/维护该索引的开销。

标签: mysql join indexing


【解决方案1】:

在此表上创建的最佳索引是什么?

  • 两个索引:col1 上的索引和col2 上的另一个索引
  • 一个双索引:两个索引col1,col2

两列索引不会像两个单列索引那样优化您的查询。

From MySQL manual,我的粗体强调:

MySQL 可以使用多列索引用于测试索引中所有列的查询,或仅测试第一列的查询、前两列、前三列等.如果您在索引定义中以正确的顺序指定列,则单个复合索引可以加快对同一张表的多种查询。

从上面的内容可以看出,当前导(最左侧)列存在约束时,MySQL 引擎可以使用多列索引。

因此,您的特定查询不会像两个单独的索引一样受益于 col1,col2 上的索引,因为考虑到您的 JOIN 子句中的 = b.col2 部分,该索引不会用于查找。

SELECT * FROM mytable a
LEFT JOIN mytable b
ON a.col1 = b.col2

至于您的“真实”数据结构,上述内容仍然适用。

注意:经验法则是先索引相等,然后索引范围。 Markus Winand 在处理索引的 his book 中支持我。

【讨论】:

    【解决方案2】:

    对于a.col1 = b.col2col1col2单独的 表中。 (不要介意它是自连接;这与创建索引无关。)

    对于更复杂的查询,再次单独考虑每个表。这些是最佳的:

    INDEX(col1, extract_date) -- in either order, and
    INDEX(col2, extract_date) -- also in either order.
    

    我同意 Marcus 并考虑;见我的Index Cookbook。而且你在“范围”处只能得到一个裂缝。

    【讨论】:

      【解决方案3】:

      你应该有两个索引。只有当WHERE 子句的形式为

      时,才能使用复合索引中的所有列
      WHERE a.col1 = something AND a.col2 = somethingelse AND a.col3 = thirdthing ...
      

      a.col1 = b.col2 这样的条件与该模式不匹配,因为ab 是表的不同实例。

      【讨论】:

      • 我认为真正的重点是 col1 和 col2 在“不同”表中。
      • @RickJames 是的,我在写答案时不知道如何表达。我已经通过在示例中添加别名来澄清。