【问题标题】:Query performance issue with multiple left joins多个左连接的查询性能问题
【发布时间】:2020-12-02 03:40:01
【问题描述】:

在 mysql v8.x 中,我有一个包含大约 7000 条记录的表。我正在尝试创建一个查询组合同一个表的两个子查询。

我认为我可以通过左连接子查询然后匹配具有这些值的任何记录来实现这一点,如下例所示(注意:当my_table 只有一个 id 列时会发生这种效果)。

当子查询返回记录时,查询似乎运行得很快,但当子查询返回空时(我在下面的示例中使用WHERE FALSE 重新创建了),查询似乎运行得很快。发生这种情况时,会自行执行这些查询,每个查询需要一毫秒左右,需要 12 秒。

我的理解是这些连接应该返回与源表相同的行数,因此不应该有这么大的差异。我有兴趣了解连接在这种情况下是如何工作的,以及为什么它会在执行时间上产生如此大的差异。

SELECT my_table.* FROM accessory_requests 
  LEFT JOIN 
     ( SELECT my_table.id 
         FROM my_table  
        WHERE FALSE
     ) as join1
    ON join1.id = my_table.id 
  LEFT JOIN 
     ( SELECT my_table.id 
         FROM my_table
        WHERE FALSE 
     ) as join2
    ON join2.id = my_table.id 
 WHERE join1.id IS NOT NULL OR join2.id IS NOT NULL;

【问题讨论】:

  • 我从未见过以 5.8 开头的 MySQL 版本。此外,您的查询在语法上不正确,因为未定义 my_table。而且您的两个联接是相同的,因此它们看起来是多余的。
  • 您实际上并不需要派生表,只需将内部查询的 where 条件移动到连接条件中即可。
  • @GordonLinoff 我的错。 mysql 应该已经阅读了 8.x,但我忘记添加一些上下文来解释为什么我在子查询中设置 WHERE FALSE。 my_table 只是一个示例,我假设它会发生在任何表上,因为它只是使用 ids 的查询。
  • @Strawberry 据我了解,这是问题的一个最小示例(生产中的真正子查询包含连接等,但没有它们就会出现问题)我试图缩小我缺乏的地方对连接的具体理解。还有什么我遗漏的东西可能会影响这里的表现吗?

标签: mysql sql performance join left-join


【解决方案1】:

组合同一张表的两个子查询。

什么意思?

如果您想从每个子查询中获取行,那么只需这样做

( SELECT ... )  -- what you are calling the first subquery
UNION 
( SELECT ... )  -- 2nd

还有,

LEFT JOIN  ( ... ) as join1  ON ...
 WHERE join1.id IS NOT NULL;

可能和简单的一样

JOIN  ( ... ) as join1  ON ...

如果“组合”是指多列,请查看标签[pivot-table]

【讨论】:

  • 谢谢。 Union 看起来是实现我想要的目标的正确方法。我只是好奇为什么那些左连接在空的情况下如此缓慢。也许我在这里遗漏了一些明显的东西,但我认为内部联接在这种情况下不会起作用,因为它只会返回匹配两个条件而不是任何一个的记录。
  • 获取EXPLAIN SELECT ... 看看发生了什么。它可能有助于获得所需的洞察力。
【解决方案2】:

您的查询全乱了,不清楚您要做什么。

但是,我可以评论您的性能问题。 MySQL 倾向于在FROM 子句中实现子查询。这意味着创建了表的新副本。这样做会丢失表上的索引。因此,消除FROM 子句中的子查询。

如果您使用示例数据、期望的结果和恰当的解释提出另一个问题,那么可能有助于使用更有效的查询形式。我怀疑你只是想要not exists,但这与这个问题相比是一个相当大的飞跃。

【讨论】:

  • 我正在尝试缩小我对连接缺乏理解的具体范围,这就是为什么我使用了一个这样的示例,除了 id 之外没有其他列。我的印象是过滤 id 不应该需要索引,因为主键总是被索引?
  • @Willbill 。 . . joins 不能使用索引,如果结果被具体化到派生表中。
  • 我认为主键是一种特殊情况,与普通索引不同,因为默认情况下您不必为 id 列定义索引。如果我对您的理解正确,则物化表没有任何索引,并且对这些表的主键进行过滤的行为就像它是未索引的列一样。感谢您的澄清。我必须承认,当子查询返回记录时,我仍然对同一查询的工作速度如此之快感到困惑,因为这些记录必须连接到基表,我预计在这种情况下性能会更差。
  • @Willbill 。 . .您的理解是正确的,在 MySQL 等优化器较差的数据库中。
猜你喜欢
  • 1970-01-01
  • 2011-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-04
  • 2014-03-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多