澄清创建临时表的连接顺序

时间:2017-01-18 19:42:59

标签: mysql join optimization explain

我在mysql中有一个大型查询,涉及将多个表连接在一起。它太慢了,所以我已经完成了"解释"并且看到它创建了一个临时表,我怀疑它占用了大部分执行时间。我找到了一些相关的信息:

  1. The mysql docs描述了创建临时表时的条件。 ("服务器在条件下创建临时表,例如 ......" [强调添加])
  2. 这个相关的SO问题Using index, using temporary, using filesort - how to fix this?,提供了指向该文档的链接并将其应用于特定情况。
  3. 这个相关的SO问题Order of join conditions important?讨论了评估联接的顺序。
  4. 我的查询似乎不符合文档#1,中列出的任何条件,这些条件是由我编写的。然而,通过实验,我发现如果我删除我的order by子句,不创建临时表。这让我从文档中看到这条规则:

      

    评估包含ORDER BY子句和不同GROUP BY子句的语句,或者ORDER BY或GROUP BY包含连接队列中第一个表以外的表中的列的语句。

    这与上面#2中的示例中的规则相同,但在#2中,OP明确地具有来自order by子句中多个表的列,因此至少在表面上不同

    此外,当我查看explain的输出时,看起来我首先列出的表不会由优化器首先使用。放下一个伪查询,例如:

    select * from A 
    join B on A.c1=B.c1
    join C on A.c2=C.c2
    where A.c3='value'
    order by A.c4
    

    我想说我的order by子句只使用联接队列中第一个表中的列" 基于我编写查询的顺序。另一方面,explain的输出表明它首先考虑表B然后是A.

    以下是问题:

    1. 上面引用的使用临时表的规则是指我编写表格的顺序还是软件选择评估它们的顺序?
    2. 如果它是我编写它们的顺序,这是否意味着连接的顺序确实会影响性能? (似乎与上面#3的说法相矛盾。)
    3. 如果它是软件选择评估它们的顺序,有没有办法强制或欺骗它选择和不使用该表的订单?

2 个答案:

答案 0 :(得分:3)

  1. 它指的是优化器评估它们的顺序(连接队列)。优化器甚至可能不知道sql语句中表的顺序。

  2. 不,它与#3中写的内容并不矛盾,因为answer明确写了(强调是我的):

  3.   

    结果

    没有影响

    结果和表现是两回事。实际上,对答案有一个赞成的评论说

      

    但它可能会影响查询计划(=>效果)​​

    1. 您可以使用straight_join

      告诉优化器首先处理哪个表
        

      STRAIGHT_JOIN类似于JOIN,只是左表始终在右表之前读取。这可以用于连接优化器以错误的顺序放置表的那些(少数)情况。

    2. 但是,你需要小心,因为你绑定了优化者的手。有关讨论straight_join的优缺点,请参阅this SO主题。

      记录数量,其中标准,索引 - 它们都在优化者对表格处理顺序的决定中发挥作用。没有灵丹妙药,你需要玩一下,可能你可以欺骗优化器来改变表的顺序。

答案 1 :(得分:1)

select * from A 
join B on A.c1=B.c1
join C on A.c2=C.c2
where A.c3='value'
order by A.c4
  • 优化器将使用各种启发式方法来决定查看表的顺序。在这种情况下,由于过滤器(A),它将以WHERE...开头。

  • A上的这个“复合”索引应该消除ORDER BYINDEX(c3, c4)的tmp& filesort。不,这与INDEX(c3), INDEX(c4)不一样。

  • A获取行后,可以访问BC(“嵌套循环加入”)。这些索引很重要:B(c1)C(c2)

  • STRAIGHT_JOINFORCE INDEX通常是一个坏主意,应该仅作为最后的手段使用。它可能有助于今天的查询,但明天会受到伤害。

  • EXPLAIN FORMAT=JSON SELECT ...提供了更多信息,有时甚至指出需要两个tmp表。

更多提示:http://mysql.rjweb.org/doc.php/index_cookbook_mysql