SQL 计划编译和真值表



如果我有NOT ( 1 <> 1 AND NULL <> 1 )

我可以看到SQL在执行计划XML中将其转换为:( 1 = 1 OR NULL = 1)

如果从字面上计算前一个表达式,则True AND Null将为 Null 并将消除该行。但是,由于 OR,编译的表达式可能会返回一行。

我可以假设这种类型的编译保证总是发生吗?SQL Server永远不会尝试将复杂的逻辑引入编译的计划吗?是否有一些关于此的文档?

这篇文章很有帮助,但我只是错过了一块拼图:https://www.simple-talk.com/sql/learn-sql-server/sql-and-the-snare-of-three-valued-logic/

下面是一个 SQL 示例

SELECT 1
FROM T T
    LEFT JOIN T2 T2 --t2 has zero rows
        ON T.id = t2.t_id
WHERE NOT ( T.id <> 99 AND T2.id <> 99 )

根据我对SQL的经验,我知道在正常情况下(没有短路评估(,T2.id <>99有效地将左连接转换为内部连接。这就是我最初期待的行为。当这个过滤器实际工作时,我很惊讶。

TL;DR "编译结果"不是一个有用的概念。重要的是"指定的结果"——由语言定义指定。DBMS 必须使语句按照您编写的方式运行。

您链接中 AND 的真相 [原文如此] 表是错误的。在 SQL 中,带有 False 的 AND 始终是 False,而带有 True 的 OR 始终是 True。


SQL 中的比较返回真、假或未知。未知可能来自与 NULL 或未知上的 3VL 逻辑连接(和/或/非等(的比较。"NULL"不是字面意思。True,False和Unknown是SQL标准中带有(分类(文字的值,但在大多数DBMS中不是。 (Unknown可以返回为NULL。IS不是比较;IS NULL 和 IS NOT NULL 是一元 3Vl 逻辑连接词,以 TRUE、FALSE 和 UNKNOWN 命名的类似连接词也是如此。它们总是返回 True 或 False。

True AND Null将为 Null 并将消除该行。然而, 编译的表达式可以返回由于 OR 而返回一行。

不。您链接中 AND 的真相 [原文如此] 表是错误的。在 SQL 中,带有 False 的 AND 始终是 False,而带有 True 的 OR 始终是 True。因此,您的 AND 始终是 False,从 1 <> 1 的 AND 中从 FALSE 的 NOT 变为 False,而您的 OR 从 1 = 1 开始始终为真。无论其他比较返回什么(真、假或未知(。如果使用(正确的(SQL 真值表处理这两个表达式,则它们始终给出相同的结果 True。

在SQL中重写条件时必须非常小心。可以通过E1 *NOT-comparison* E2NOT (E IS ?)E IS NOT ?交换NOT (E1 *comparison* E2)。如果没有值为 NULL,则可以使用标准逻辑标识/规则安全地重写表达式。还可以安全地将重写规则应用于

    (E1 *comparison* E2)
AND E1 IS NOT NULL AND E2 IS NOT NULL

另请注意,您必须正确使用未知最终结果,其中包括不匹配 WHERE 但不匹配约束。

SELECT 1
FROM T T
    LEFT JOIN T2 T2 --t2 has zero rows
        ON T.id = t2.t_id
WHERE NOT ( T.id <> 99 AND T2.id <> 99 )

LEFT JOIN 返回 INNER JOIN 的行以及由 T2 列 NULL 扩展的不匹配的 T 行。(当 T2 为空时,内部联接为空,并且 T 的所有行都不匹配。所有扩展行都 T2.id <> 99 未知,因为 T2.id 为 NULL。对于 T.id = 99,AND 为假,NOT 为真;WHERE 返回所有行。对于 T1.id 任何其他整数或 NULL,AND 将为"未知",NOT 将为"未知";WHERE 不返回任何行。

(在SQL中没有对条件的"短ciruit"评估。必须定义连接词的每个参数。

如果从字面上计算前一个表达式,则 True AND Null 将为 Null,并将消除该行。

不。您正在评估表达式。 NOT ( 1 <> 1 AND NULL <> 1 )NOT (FALSE AND UNKNOWN)NOT FALSETRUE

( 1 = 1 OR NULL = 1)TRUE OR UNKNOWNTRUE.它们都是等效的。


NOT ( 1 <> 1 AND NULL <> 1 )可以重写为 NOT ((NOT (1=1)) AND (NOT (NULL = 1))) .在正则的两个值逻辑中,由德摩根定律可以重写为NOT (NOT ((1 = 1) OR (NULL = 1)))然后(1=1) OR (NULL = 1)。事实证明,德摩根定律也适用于SQL的三个值逻辑。这可以通过为这两个定律创建详尽的真值表来证明。

真值表显示德摩根定律之一,(NOT A) OR (NOT B)等价于NOT (A AND B),在SQL的三个值逻辑中成立:

A  B | (NOT A)  OR  (NOT B) | equiv? | NOT (A  AND  B)
========================================================
T  T |   F  T   F     F  T  |   T    |  F   T   T   T
T  F |   F  T   T     T  F  |   T    |  T   T   F   F
T  U |   F  T   U     U  U  |   T    |  U   T   U   U
-------------------------------------------------------
F  T |   T  F   T     F  T  |   T    |  T   F   F   T
F  F |   T  F   T     T  F  |   T    |  T   F   F   F
F  U |   T  F   T     U  U  |   T    |  T   F   F   U
-------------------------------------------------------
U  T |   U  U   U     F  T  |   T    |  U   U   U   T
U  F |   U  U   T     T  F  |   T    |  T   U   F   F
U  U |   U  U   U     U  U  |   T    |  U   U   U   U

另一个定律,(NOT A) AND (NOT B)等同于NOT (A OR B)同样可以证明。


我可以假设这种类型的编译保证总是发生吗?

,从不(几乎从不(保证特定的编译。除非 SQL Server 中存在错误,否则所选的查询计划、应用的转换将返回查询指定的结果。


编辑补充:T.id 99T2.id NULL。然后:

  • WHERE NOT ( T.id <> 99 AND T2.id <> 99 )
  • WHERE NOT (99 <> 99 AND NULL <> 99)
  • WHERE NOT (FALSE AND UNKNOWN)
  • WHERE NOT (FALSE)
  • WHERE TRUE

最新更新