SQL计划编译和真值表
如果我有SQL计划编译和真值表,sql,sql-server,null,left-join,Sql,Sql Server,Null,Left Join,如果我有NOT(1和空1) 我可以看到SQL在执行计划XML中将此转换为:(1=1或NULL=1) 如果您逐字计算前一个表达式,True和Null将为Null,并将删除该行。但是,编译后的表达式可以返回一行,原因是OR 我是否可以假设这种类型的编译保证总是发生?SQL Server永远不会尝试将复杂的逻辑向前推进到已编译的计划中?有关于这方面的文件吗 这篇文章很有帮助,但我只是错过了一个难题: 下面是一个SQL示例 SELECT 1 FROM T T LEFT JOIN T2 T2 -
NOT(1和空1)
我可以看到SQL在执行计划XML中将此转换为:(1=1或NULL=1)
如果您逐字计算前一个表达式,True和Null
将为Null,并将删除该行。但是,编译后的表达式可以返回一行,原因是OR
我是否可以假设这种类型的编译保证总是发生?SQL Server永远不会尝试将复杂的逻辑向前推进到已编译的计划中?有关于这方面的文件吗
这篇文章很有帮助,但我只是错过了一个难题:
下面是一个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 )
选择1
从T
左连接T2--T2有零行
在T.id=t2.T\u id上
如果不是(T.id 99和T2.id 99)
根据我使用SQL的经验,我知道在正常情况下(没有短路计算),T2.ID99有效地将左连接转换为内部连接。这是我最初期待的行为。当这个过滤器实际工作时,我感到惊讶。TL;DR编译结果”不是一个有用的概念。重要的是“指定的结果”——由语言定义指定。DBMS必须使语句按您编写的方式运行 链接中的和的真相[原文]表是错误的。在SQL中,with False始终为False,with True始终为True
SQL中的比较返回True、False或Unknown。未知可能来自对未知的NULL或3VL逻辑连接(和/或/或非等)的比较。“NULL”不是文本。True、False和Unknown在SQL标准中是具有(分类)文本的值,但在大多数DBMS中不是。(Unknown可以返回为NULL。)不是比较;IS NULL和IS NOT NULL是一元3Vl逻辑连接词,以TRUE、FALSE和UNKNOWN命名的类似连接词也是一元3Vl逻辑连接词。它们总是返回真或假
True和Null
将为Null并删除该行。但是,
由于或,编译表达式可以返回一行
不。你链接中的和的真相[原文]表是错误的。在SQL中,with False始终为False,with True始终为True。所以你的和总是假的,从1到1,你的和总是假的,从1=1。无论其他比较结果如何(真、假或未知)。如果您使用来处理这两个表达式,它们总是给出相同的结果,True
在SQL中重写条件时必须非常小心。人们可以通过E1*不比较*E2
或NOT(E是?
和E不是?
交换NOT(E1*比较*E2)
。如果没有任何值为NULL,则可以使用标准逻辑标识/规则安全地重写表达式。还可以安全地将重写规则应用于
(E1 *comparison* E2)
AND E1 IS NOT NULL AND E2 IS NOT NULL
还要注意,您必须正确使用未知的最终结果,其中包括不匹配WHERE但不失败约束
选择1
从T
左连接T2--T2有零行
在T.id=t2.T\u id上
如果不是(T.id 99和T2.id 99)
LEFT JOIN返回内部联接的行加上由T2列NULL扩展的不匹配的T行。(T2为空时,内部联接为空,T的所有行都不匹配。)由于T2.id为NULL,所有扩展行的T2.id 99未知。对于T.id=99,AND为假,NOT为真;WHERE返回所有行。对于T1.id任何其他整数或NULL,AND将是未知的,NOT将是未知的;WHERE不返回任何行
(SQL中没有条件的“短回路”计算。必须定义连接词的每个参数。)
如果您逐字计算前一个表达式,则True和Null将为Null,并将删除该行
不,您正在计算表达式<代码>非(1 1和空1)为非(假和未知)
为非假
为真
(1=1或NULL=1)
为真或未知
为真
。它们都是等价的
NOT(1和NULL 1)
可以重写为NOT((NOT(1=1))和(NOT(NULL=1))
。在常规的two值逻辑中,可以将其重写为NOT(NOT((1=1)或(NULL=1))
,然后再重写(1=1)或(NULL=1)
。事实证明,德摩根定律在SQL的三值逻辑中也成立。这可以通过为这两条定律创建详尽的真值表来证明
真值表显示德摩根定律之一,(非A)或(非B)
相当于非(A和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
另一条定律,(非A)和(非B)
等同于非(A或B)
也可以类似地证明
我是否可以假设这种类型的编译保证总是发生 不,特定的编译永远(几乎永远)不能保证。除非SQL Server中存在bug,否则选择的查询计划和应用的转换将返回查询指定的结果
编辑以添加:让
T.id
be99
和T2.id
beNULL
。然后:
其中没有(T.id 99和T2.id 99)
WHERE NOT(99和NULL 99)
WHERE NOT(错误和未知)
WHERE NOT(FALSE)
其中TRUE
- 你所说的
True
是什么意思?SQL不允许以这种方式相互比较布尔值。你所说的真和空是什么意思NULL
是一段数据的占位符。SQL没有布尔数据。第三个布尔值是UNKNOWN
。是的,我对列值使用占位符,而不是(1和NULL 1)@shawnt00。以三值日志的方式
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