以下是我遇到的问题的一些复制代码。
在SQL SERVER 2017中运行它,与任何其他SQL SERVER版本相比,您将获得不同(且不正确)的结果将数据库设置为在sql Server 2017实例上具有较低的兼容性级别,它也可以正常工作。
为什么会发生这种情况?如何在不更改兼容级别的情况下进行修复?
for i in states:
if i == "New York":
dataset["New York"].replace("", 1)
+--------------+--------------+----------------+---------+-----------+---------+------------+-------+
| IsPriorAfter | IsIdealAfter | IsCurrentAfter | IsPrior | IsCurrent | IsIdeal | SecurityID | PosID |
+--------------+--------------+----------------+---------+-----------+---------+------------+-------+
| 1 | 1 | 1 | 1 | 1 | 1 | 123 | 1 |
| 0 | 0 | 0 | 0 | 1 | 1 | 234 | 2 |
| 0 | 0 | 0 | 1 | 0 | 0 | 234 | 3 |
+--------------+--------------+----------------+---------+-----------+---------+------------+-------+
+--------------+--------------+----------------+---------+-----------+---------+------------+-------+
| IsPriorAfter | IsIdealAfter | IsCurrentAfter | IsPrior | IsCurrent | IsIdeal | SecurityID | PosID |
+--------------+--------------+----------------+---------+-----------+---------+------------+-------+
| 1 | 1 | 1 | 1 | 1 | 1 | 123 | 1 |
| 0 | 1 | 1 | 0 | 1 | 1 | 234 | 2 |
| 1 | 0 | 0 | 1 | 0 | 0 | 234 | 3 |
+--------------+--------------+----------------+---------+-----------+---------+------------+-------+
答案 0 :(得分:2)
TLDR
这是a bug that has been fixed in CU8,因此至少安装该CU,最好安装最新的CU即可解决。
SQL Server 2017之前的版本
在SQL Server 2016中,计划如下所示。 IN
与EXISTS
的处理方式相同,因此它会评估以下三列。
CASE WHEN IsPrior = 1 AND EXISTS (SELECT * FROM ForSubQuery WHERE SecID = MainTable.SecurityID) THEN 1 ELSE 0 END AS IsPriorAfter
CASE WHEN IsIdeal = 1 AND EXISTS (SELECT * FROM ForSubQuery WHERE SecID = MainTable.SecurityID) THEN 1 ELSE 0 END AS IsIdealAfter
CASE WHEN IsCurrent = 1 AND EXISTS (SELECT * FROM ForSubQuery WHERE SecID = MainTable.SecurityID) THEN 1 ELSE 0 END AS IsCurrentAfter
每个子查询实例在计划中都有其自己的运算符,并且查询返回正确的结果,但这是次优的,因为同一子查询每行最多可以执行多达次。
因为每个子查询旁边都有一个AND
,但是如果该表达式的结果为false,SQL Server可以跳过对子查询的评估。这是通过每个包含通过谓词的嵌套循环来实现的。例如,与IsPriorAfter
的求值相对应的一个具有IsFalseOrNull (IsPrior=1)
的通过谓词
IsPrior=1
是一个布尔表达式,可以返回false
,null
或true
。然后IsFalseOrNull
反转结果,并为1
返回false
,为null
返回0
。因此,如果true
不是true
(包括1
)之外的任何事物,则通过谓词的评估结果为IsPrior
/ 1
,然后跳过执行子查询。
SQL Server 2017 RTM
SQL Server 2017引入了新的优化规则CollapseIdenticalScalarSubquery
。在RTM版本中,执行计划不正确。
问题计划
子查询现在在单个运算符中,并且通过谓词进行了组合
NULL
但是这种情况不正确!除非IsFalseOrNull([IsCurrent]=(1)) OR IsFalseOrNull([IsIdeal]=(1)) OR IsFalseOrNull([IsPrior]=(1))
,true
,IsPrior
中的三个所有为IsIdeal
,否则它的值为IsCurrent
。
因此,在您的情况下,子查询仅执行一次(对于表的第一行-其中所有三列均等于1)。
对于其他两行,应执行但不执行。嵌套循环具有一个探针列,如果相关子查询返回一行,则该探针列设置为1
。 (在计划中用1
标记)。当跳过执行时,此探针列设置为Expr1016
计划中的最终计算标量具有以下表达式。当NULL
为Expr1016
时,对于使用null
计算的所有三个列,其求值为0
。
CASE
已修补SQL Server 2017
应用CU后的最终固定计划具有与2017 RTM计划相同的计划形状(子查询仅出现一次),但现在通过谓词
[Expr1005] = Scalar Operator(CASE WHEN [IsPrior]=(1) AND [Expr1016] THEN (1) ELSE (0) END),
[Expr1009] = Scalar Operator(CASE WHEN [IsIdeal]=(1) AND [Expr1016] THEN (1) ELSE (0) END),
[Expr1013] = Scalar Operator(CASE WHEN [IsCurrent]=(1) AND [Expr1016] THEN (1) ELSE (0) END)
仅当这些列中的无的值为IsFalseOrNull([IsCurrent]=(1)) AND IsFalseOrNull([IsIdeal]=(1)) AND IsFalseOrNull([IsPrior]=(1))
时,此评估结果才为true
,因此现在可以在需要时准确地评估子查询。