SQL 计划编译和真值表

SQL plan compilation and truth tables

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

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

如果您按字面意思计算前一个表达式,则 True AND Null 将为 Null 并会删除该行。但是,由于 OR.

,编译后的表达式可以 return 一行

我可以假设这种类型的编译总是会发生吗? SQL 服务器永远不会尝试将复杂的逻辑推进到编译计划中?有这方面的文件吗?

这篇文章很有帮助,但我只是漏掉了一块拼图: 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 "compiled result" 不是一个有用的概念。重要的是 "specified result"-- 由语言定义指定。 DBMS 必须使语句按照您编写的方式运行。

你 link 中的 AND table 的真相 是错误的。在 SQL.

中,AND 与 False 始终为 False,OR 与 True 始终为 True

SQL 中的比较 return 真、假或未知。 Unknown 可能来自与 NULL 或 Unknown 上的 3VL 逻辑连接符(AND/OR/NOT 等)的比较。 "NULL" 不是文字。 True、False 和 Unknown 是 SQL 标准中具有(分类)文字的值,但在大多数 DBMS 中没有。 (并且 Unknown 可以 returned 为 NULL。)IS 不是比较; IS NULL 和 IS NOT NULL 是一元 3Vl 逻辑连接词,类似的以 TRUE、FALSE 和 UNKNOWN 命名的连接词也是如此。他们总是 return 对或错。

True AND Null would be Null and would eliminate the row. However, the compiled expression can return a row due to the OR.

没有。在你的 link 中,AND 的 [sic] table 的真相是 错误的 。在 SQL 中,AND 与 False 始终为 False,OR 与 True 始终为 True。因此,从 1 <> 1 的 AND 和 False,您的 AND 始终为 False,而 1 = 1 的 OR 始终为 True。无论其他比较 return(True、False 或 Unknown) .如果您使用 the (correct) SQL truth tables) 处理这两个表达式,它们总是给出相同的结果,True。

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

    (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 returns INNER JOIN 的行加上由 T2 列 NULL 扩展的 T 的不匹配行。 (T2 为空时,INNER JOIN 为空,T 的所有行都不匹配。)所有扩展行都有 T2.id <> 99 Unknown,因为 T2.id 为 NULL。对于 T.id = 99,AND 为 False,NOT 为 True; WHERE returns 所有行。对于 T1.id 任何其他整数或 NULL,AND 将是未知的,NOT 将是未知的; WHERE return 没有行。

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

If you would literally evaluate the former expression, the True AND Null would be Null and would eliminate the row.

没有。您正在评估表达式。 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)))。在常规 two 值逻辑中,由 De Morgan's Laws 可以重写为 NOT (NOT ((1 = 1) OR (NULL = 1))) 然后 (1=1) OR (NULL = 1)。事实证明,德摩根定律 在 SQL 的三值逻辑中也成立 。这可以通过为这两个定律创建详尽的真理 tables 来证明。

真理table表明德摩根定律之一(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),同样可以证明


Can I assume that this type of compilation is guaranteed to always happen?

不,从不(几乎从不)保证特定的编译。排除 SQL 服务器中的错误,选择的查询计划,应用的转换将 return 查询指定的结果。


编辑添加:T.id99T2.idNULL。那么:

  • 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