Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server WHERE子句最好在IN和JOIN之前或之后执行_Sql Server - Fatal编程技术网

Sql server WHERE子句最好在IN和JOIN之前或之后执行

Sql server WHERE子句最好在IN和JOIN之前或之后执行,sql-server,Sql Server,我读了这篇文章: 在文章末尾已被写入并加入条款考虑在哪里。 假设我们有一个记录了1000万条记录的主表和一个记录了5000万条记录的细节表(引用了主表(FK))。我们有一个查询,根据主表中的PK,不只是100条细节表记录 在这种情况下,加入和执行在哪里?我的意思是,我们在加入之后有500毫秒记录,然后在哪里应用它呢?还是先申请,然后加入,再考虑?如果第二个答案是真的,它与顶部文章有不一致性吗? 谢谢我想你把上的误读为中的 但是,文章中显示的顺序是正确的(显然它是msdn)。上的和连接在其中之前

我读了这篇文章:

在文章末尾已被写入并加入条款考虑在哪里。

假设我们有一个记录了1000万条记录的主表和一个记录了5000万条记录的细节表(引用了主表(FK))。我们有一个查询,根据主表中的PK,不只是100条细节表记录

在这种情况下,加入和执行在哪里?我的意思是,我们在加入之后有500毫秒记录,然后在哪里应用它呢?还是先申请,然后加入,再考虑?如果第二个答案是真的,它与顶部文章有不一致性吗?


谢谢

我想你把上的误读为中的

但是,文章中显示的顺序是正确的(显然它是msdn)。
上的
连接
其中
之前自然执行,因为
其中
必须作为过滤器应用于由于
连接而获得的临时结果集

这篇文章只是说这是执行的逻辑顺序,而且在这一段的末尾也添加了这一行;)


“请注意,语句的实际物理执行由查询处理器决定,顺序可能与此列表不同。”

没有定义的顺序。SQL引擎根据优化器选择的执行策略确定执行操作的顺序。

这无关紧要

始终遵守逻辑处理顺序:无论实际处理顺序如何

内部连接和WHERE条件是有效的关联和交换的(因此ANSI-89“在WHERE中连接”语法),因此实际顺序并不重要

对于外部联接和更复杂的查询,逻辑顺序变得非常重要:在外部表上应用WHERE将完全改变逻辑

同样,只要查询语义是按照逻辑处理顺序维护的,那么优化程序在内部如何进行并不重要


这里的关键词是“optimizer”:它完全按照它所说的去做

在一个内部联接或一个左联接中左边的表的情况下,在许多情况下,优化器会发现最好先执行任何过滤(最高选择性)在实际执行任何类型的物理连接之前-显然有更好的物理操作顺序

在某种程度上,您有时可以通过SQL控制(或干预),例如,通过子查询中的聚合

处理查询中约束的逻辑顺序只能根据已知的不变变换进行变换

因此:

在逻辑上仍然等同于:

SELECT *
FROM a
INNER JOIN b
    ON a.id = b.id
    AND a.something = something
    AND b.something = something
SELECT *
FROM a
LEFT JOIN b
    ON a.id = b.id
    AND a.something = something
    AND b.something = something
他们通常会有相同的执行计划

另一方面:

SELECT *
FROM a
LEFT JOIN b
    ON a.id = b.id
WHERE a.something = something
    AND b.something = something
不等同于:

SELECT *
FROM a
INNER JOIN b
    ON a.id = b.id
    AND a.something = something
    AND b.something = something
SELECT *
FROM a
LEFT JOIN b
    ON a.id = b.id
    AND a.something = something
    AND b.something = something
因此优化器不会将它们转换为相同的执行计划

优化器非常智能,能够非常成功地移动对象,包括折叠视图和内联表值函数,甚至可以非常成功地通过某些聚合向下推送对象


通常,当您编写SQL时,它需要是可理解的、可维护的和正确的。就执行效率而言,如果优化器很难将声明性SQL转换为具有可接受性能的执行计划,代码有时可以简化,或者添加适当的索引或提示,或者分解成执行速度更快的步骤——所有步骤都是以连续的入侵顺序进行的。

只要重新阅读Paul White的并记住这个问题

可以使用未记录的命令禁用特定的转换规则,并深入了解应用的转换

出于(希望如此!)明显的原因,请仅在开发实例上尝试此操作,并记住重新启用它们,并从缓存中删除任何不理想的计划。
使用AdventureWorks2008;
/*禁用规则*/
DBCC规则关闭(“SELonJN”);
DBCC规则关闭(“构建假脱机”);
选择P.ProductNumber,
P.ProductID,
一、数量
来自生产。产品P
加入Product.ProductInventory I
关于I.ProductID=P.ProductID
其中I.ProductID<3
选项(重新编译)
您可以看到,禁用这两个规则后,它会进行笛卡尔连接并在之后进行过滤

/*Re-enable them*/   
DBCC RULEON ('SELonJN');
DBCC RULEON ('BuildSpool');

 SELECT  P.ProductNumber, 
         P.ProductID, 
        I.Quantity
 FROM    Production.Product P
 JOIN    Production.ProductInventory I
         ON  I.ProductID = P.ProductID
WHERE I.ProductID < 3
OPTION (RECOMPILE)

/*重新启用它们*/
DBCC规则(“SELonJN”);
DBCC规则(“构建假脱机”);
选择P.ProductNumber,
P.ProductID,
一、数量
来自生产。产品P
加入Product.ProductInventory I
关于I.ProductID=P.ProductID
其中I.ProductID<3
选项(重新编译)
启用它们后,谓词将被直接下推到索引查找中,从而减少联接操作处理的行数


关键词是“逻辑”。这不是SQL Server实际所做的!您的链接上写着“请注意,语句的实际物理执行由查询处理器决定,顺序可能与此列表不同。”有一个逻辑顺序是值得遵守的,无论实际使用的顺序是什么。我很难理解您的
左连接
示例。为什么它不是等价的?
WHERE
是否适用于联接结果?@Toskan在后者中,如果
a.id=b.id
a.something=something
b.something=something
计算为false,则返回一行
b
字段的空值;在前者中,如果
a.something=something
b.something=something
的计算结果为false,则不会返回一行。@MattArnold,谢谢。因此,简而言之:
只要a.id=b.id上有行,左连接b将始终返回一些内容。基本上,
在a.id=b.id上左连接b
就像在说“如果您与
b.id
匹配就好了,但是如果您不能