澄清创建临时表的连接顺序
Clarification of join order for creation of temporary tables
我在 mysql 中有一个大型查询,涉及将多个 table 连接在一起。它太慢了,所以我完成了 "explain" 并看到它正在创建一个临时的 table,我怀疑它占用了大部分执行时间。我找到了一些相关资料:
- The mysql docs 描述创建临时 table 可能 的条件。 ("The server creates temporary tables under conditions such as these..." [强调])
- 这个相关的 SO 问题 Using index, using temporary, using filesort - how to fix this?,它为文档提供了 link 并将其应用于特定情况。
- 这个相关的 SO 问题 Order of join conditions important? 讨论了计算连接的顺序。
我的查询似乎不满足文档 #1 中列出的任何条件,按照我编写连接的顺序。但是,通过实验,我发现如果我删除 order by
子句,则不会创建临时 table。这让我从文档中看到了这条规则:
Evaluation of statements that contain an ORDER BY clause and a different GROUP BY clause, or for which the ORDER BY or GROUP BY contains columns from tables other than the first table in the join queue.
这与上面 #2 示例中的规则相同,但在 #2 中,OP 在 order by
子句中明确包含来自多个 table 的列,因此位于至少表面上不同。
此外,当我查看 explain
的输出时,我首先列出的 table 似乎并没有被优化器首先使用。例如写一个伪查询:
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
子句确实仅使用 "first table in the join queue" 中的列,基于我编写查询的顺序。 上另一方面,explain
的输出表明它首先考虑 table B,然后是 A.
下面是问题:
- 上面引用的使用临时table的规则是指我编写table的顺序还是软件选择评估它们的顺序?
- 如果这是我编写它们的顺序,这是否意味着连接的顺序确实会影响性能? (似乎与上面#3 的说法相矛盾。)
- 如果软件选择评估它们的顺序,是否有任何方法可以强制或欺骗它选择不使用 table 的顺序?
指的是优化器对它们求值的顺序(加入队列)。优化器甚至可能不知道 sql 语句中 table 的顺序。
不,它与#3 中的内容并不矛盾,因为 answer 明确写道(重点是我的):
has no effect on the result
结果和表现是两个不同的东西。实际上,对答案有一个赞成的评论说
But it might affect the query plan (=> performance)
您可以使用 straight_join:
告诉优化器首先处理哪个 table
STRAIGHT_JOIN is similar to JOIN, except that the left table is always read before the right table. This can be used for those (few) cases for which the join optimizer puts the tables in the wrong order.
但是,你需要小心,因为你束缚了优化者的手。请参阅 this SO 讨论 straight_join 优缺点的主题。
记录数、条件、索引 - 它们都在优化器决定 tables 的处理顺序中发挥作用。没有灵丹妙药,您需要稍微尝试一下,也许您可以欺骗优化器来更改 table 的顺序。
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
优化器将使用各种试探法来决定查看表的顺序。在这种情况下,由于过滤器 (WHERE...
).
,它将以 A
开头
A
上的这个 "composite" 索引应该消除 ORDER BY
的 tmp 和文件排序:INDEX(c3, c4)
。不,这与 INDEX(c3), INDEX(c4)
.
不同
从 A
获取行后,B
或 C
可以到达 ("Nested Loop Join")。这些索引很重要:B
:(c1)
和 C
:(c2)
.
STRAIGHT_JOIN
和 FORCE INDEX
通常不是一个好主意,只能作为最后的手段使用。它可能对今天的查询有帮助,但对明天有伤害。
EXPLAIN FORMAT=JSON SELECT ...
给出了更多信息,有时甚至指出需要两个tmp表。
我在 mysql 中有一个大型查询,涉及将多个 table 连接在一起。它太慢了,所以我完成了 "explain" 并看到它正在创建一个临时的 table,我怀疑它占用了大部分执行时间。我找到了一些相关资料:
- The mysql docs 描述创建临时 table 可能 的条件。 ("The server creates temporary tables under conditions such as these..." [强调])
- 这个相关的 SO 问题 Using index, using temporary, using filesort - how to fix this?,它为文档提供了 link 并将其应用于特定情况。
- 这个相关的 SO 问题 Order of join conditions important? 讨论了计算连接的顺序。
我的查询似乎不满足文档 #1 中列出的任何条件,按照我编写连接的顺序。但是,通过实验,我发现如果我删除 order by
子句,则不会创建临时 table。这让我从文档中看到了这条规则:
Evaluation of statements that contain an ORDER BY clause and a different GROUP BY clause, or for which the ORDER BY or GROUP BY contains columns from tables other than the first table in the join queue.
这与上面 #2 示例中的规则相同,但在 #2 中,OP 在 order by
子句中明确包含来自多个 table 的列,因此位于至少表面上不同。
此外,当我查看 explain
的输出时,我首先列出的 table 似乎并没有被优化器首先使用。例如写一个伪查询:
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
子句确实仅使用 "first table in the join queue" 中的列,基于我编写查询的顺序。 上另一方面,explain
的输出表明它首先考虑 table B,然后是 A.
下面是问题:
- 上面引用的使用临时table的规则是指我编写table的顺序还是软件选择评估它们的顺序?
- 如果这是我编写它们的顺序,这是否意味着连接的顺序确实会影响性能? (似乎与上面#3 的说法相矛盾。)
- 如果软件选择评估它们的顺序,是否有任何方法可以强制或欺骗它选择不使用 table 的顺序?
指的是优化器对它们求值的顺序(加入队列)。优化器甚至可能不知道 sql 语句中 table 的顺序。
不,它与#3 中的内容并不矛盾,因为 answer 明确写道(重点是我的):
has no effect on the result
结果和表现是两个不同的东西。实际上,对答案有一个赞成的评论说
But it might affect the query plan (=> performance)
您可以使用 straight_join:
告诉优化器首先处理哪个 tableSTRAIGHT_JOIN is similar to JOIN, except that the left table is always read before the right table. This can be used for those (few) cases for which the join optimizer puts the tables in the wrong order.
但是,你需要小心,因为你束缚了优化者的手。请参阅 this SO 讨论 straight_join 优缺点的主题。
记录数、条件、索引 - 它们都在优化器决定 tables 的处理顺序中发挥作用。没有灵丹妙药,您需要稍微尝试一下,也许您可以欺骗优化器来更改 table 的顺序。
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
优化器将使用各种试探法来决定查看表的顺序。在这种情况下,由于过滤器 (
WHERE...
). ,它将以 A
上的这个 "composite" 索引应该消除ORDER BY
的 tmp 和文件排序:INDEX(c3, c4)
。不,这与INDEX(c3), INDEX(c4)
. 不同
从
A
获取行后,B
或C
可以到达 ("Nested Loop Join")。这些索引很重要:B
:(c1)
和C
:(c2)
.STRAIGHT_JOIN
和FORCE INDEX
通常不是一个好主意,只能作为最后的手段使用。它可能对今天的查询有帮助,但对明天有伤害。EXPLAIN FORMAT=JSON SELECT ...
给出了更多信息,有时甚至指出需要两个tmp表。
A
开头