我在mysql中有一个大型查询,涉及将多个表连接在一起。它太慢了,所以我已经完成了"解释"并且看到它创建了一个临时表,我怀疑它占用了大部分执行时间。我找到了一些相关的信息:
我的查询似乎不符合文档#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.
以下是问题:
答案 0 :(得分:3)
它指的是优化器评估它们的顺序(连接队列)。优化器甚至可能不知道sql语句中表的顺序。
不,它与#3中写的内容并不矛盾,因为answer明确写了(强调是我的):
对结果
没有影响
结果和表现是两回事。实际上,对答案有一个赞成的评论说
但它可能会影响查询计划(=>效果)
您可以使用straight_join:
告诉优化器首先处理哪个表STRAIGHT_JOIN类似于JOIN,只是左表始终在右表之前读取。这可以用于连接优化器以错误的顺序放置表的那些(少数)情况。
但是,你需要小心,因为你绑定了优化者的手。有关讨论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 BY
:INDEX(c3, c4)
的tmp& filesort。不,这与INDEX(c3), INDEX(c4)
不一样。
从A
获取行后,可以访问B
或C
(“嵌套循环加入”)。这些索引很重要:B
:(c1)
和C
:(c2)
。
STRAIGHT_JOIN
和FORCE INDEX
通常是一个坏主意,应该仅作为最后的手段使用。它可能有助于今天的查询,但明天会受到伤害。
EXPLAIN FORMAT=JSON SELECT ...
提供了更多信息,有时甚至指出需要两个tmp表。