如果我运行以下 SQL 查询
SELECT *
FROM A
LEFT JOIN B
ON A.foo=B.foo
WHERE A.date = "Yesterday"
该WHERE
语句是在 ? 之前还是之后进行评估的JOIN
?
如果之后,编写此语句的更好方法是什么,以便仅返回A
from"Yesterday"
中的行 join to B
?
如果我运行以下 SQL 查询
SELECT *
FROM A
LEFT JOIN B
ON A.foo=B.foo
WHERE A.date = "Yesterday"
该WHERE
语句是在 ? 之前还是之后进行评估的JOIN
?
如果之后,编写此语句的更好方法是什么,以便仅返回A
from"Yesterday"
中的行 join to B
?
这取决于数据库。
在 SQL Server 上,运行:SET SHOWPLAN_ALL ON
然后运行查询,您将了解它运行时会发生什么。
您对“评估”的想法是不正确的,因为 SQL 是一种声明性语言。
顺便说一句,您可以看到查询执行计划。在 MySQL 中为您的查询添加关键字前缀describe
以查看执行计划。
语义上:在 JOIN 之后。但在这种情况下,时间上没有区别,因为它在 JOIN 的左侧。
正如您已经拥有的那样,“只有来自“昨天”的 A 中的行才连接到 B”。
优化器可以根据关系代数中的等价性自由地重新组织其操作顺序。
这仅返回 A.date="Yesterday" 并加入 B,它可以在 foo 上找到匹配项:
SELECT * FROM A
LEFT JOIN B
ON A.foo=B.foo
WHERE A.date="Yesterday"
无论任何条件如何,这都会返回所有 A 并加入 B 其中 A.date="Yesterday" 并且它在 foo 上找到匹配项:
SELECT * FROM A
LEFT JOIN B
ON A.foo=B.foo
AND A.date="Yesterday"
满足查询的操作顺序决定了为什么特定数据库的查询优化器会心血来潮。查询优化器试图根据它可以从查询中收集到的信息以及它现有的关于数据库的任何统计信息(可能包括表的基数和数据的某些分布)来生成一个好的“查询计划”(一组操作) .
在您的情况下,答案可能取决于您是否在 A.date 上有二级索引
查询优化是一个相当丰富的话题。您使用的任何数据库的文档都会有更多的说明。
在 SQL Server 中:
作为一般经验法则,JOIN 子句在 WHERE 子句之前进行评估。
如果在连接部分需要过滤器的复杂连接,我将它们与我的连接一起编写
SELECT *
FROM A
LEFT JOIN B
ON A.Foo1 = B.Foo1
And A.Date = 'Yesterday'
OUTER JOIN C
ON B.Foo2 = C.Foo2
JOIN D
ON B.Foo3 = D.Foo3
取决于索引和统计数据。
您应该显示查询的执行路径以确定应该在哪里应用优化(如果有的话)。
SELECT *
FROM (SELECT * FROM A WHERE Date = 'Yesterday') A
LEFT JOIN B
ON A.Foo1 = B.Foo1
OUTER JOIN C
ON B.Foo2 = C.Foo2
JOIN D
ON B.Foo3 = D.Foo3