我一直在到处寻找,但我找不到任何关于它的东西,似乎每个人都只关心 WHERE 和 CASE。(而且我手头没有 SQL Server 自己来验证它)
所以,一个简单的问题:SQL Server 是否基于 JOIN 条件短路 JOIN?如果我写:
TableA LEFT OUTER JOIN TableB ON 1=0 AND TableA.ID = TableB.A_ID
SQL Server 会完全跳过连接吗?
编辑
好的,有人正确地指出,这是在编译时解决的,所以我最好扩展这个问题。
以上只是作为一个例子,但结果证明是一个糟糕的例子。我想知道的是,当这种情况在运行时发生时,SQL Server 是否会使 JOIN 短路,作为传递给存储过程的@parameter 的结果。
我之所以问,是因为我肯定在过去几年中使用过类似的东西,但在与一些同事谈论它之前,我想 100% 确定。那么,SQL Server 是否会将其短路,然后:
TableA LEFT OUTER JOIN TableB ON @parameter IS NOT NULL AND TableA.ID = TableB.A_ID
如果它在 SP 内并且在 @parameter 设置为 NULL 的情况下调用它?如果存储过程是 WITH RECOMPILE,它会有什么不同吗?
DB<>fiddle和其他在线服务允许您测试不同的 DBMS,而无需在本地安装它们。如图所示:
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=7692d5abba854bdc57d90c95335014c0
无法访问表 B。
您可能会发现 Lukas Eder 感兴趣的以下文章,他比较了不同 DBMS 的代数优化:
https://blog.jooq.org/2017/09/28/10-cool-sql-optimisations-that-do-not-depend-on-the-cost-model/
数据设置
存储过程
执行后的计划
EXEC P1 1
如下所示。但是,估计的行数取决于编译计划时传递的参数值。如果
NULL
已通过,则最终运算符中的估计行数为1.37074
. 在这个简单的计划中,可以为估计有 1.37 行的子树发出 218 行这一事实可能不会有太大区别,但如果这是更大查询的一部分,它可以做到。即使在这个简单的例子中,它也可能意味着最终哈希连接的内存授予是不正确的。从逻辑上讲,外连接不能减少行数,但由于某种原因,最初的 3 在通过此处的其他两个外连接后会缩小到 1.37074。
如果需要稍微准确的基数估计,那么
WITH RECOMPILE
确实可以解决这个问题 - 基数估计要么1.37074
取决于218
参数的可空性,要么取决于参数的可空性。但OPTION (RECOMPILE)
会更可取。除了针对特定声明外,它还允许进行额外的简化。With
OPTION (RECOMPILE)
in place 调用 with 时的执行计划NULL
如下。实际行和估计行都在现场,并且所有冗余运算符都已从计划中删除(因此在这种情况下,它不会花时间为不需要的哈希连接创建构建输入)。
以上计划在构建 14.0.1000.169 上生成