“不为空”和“不为空”有啥区别

Posted

技术标签:

【中文标题】“不为空”和“不为空”有啥区别【英文标题】:What is the difference between "Is Not Null" and "Not Is Null"“不为空”和“不为空”有什么区别 【发布时间】:2011-05-03 11:34:24 【问题描述】:
SELECT id FROM customers WHERE type IS NOT Null;

对比:

SELECT id FROM customers WHERE NOT type IS NULL;

以上任何一个返回的数据都将完全相同。

有什么区别,为什么其中一种更可取?

编辑: 在我看来,在性能方面可能会有所不同。有人愿意详细说明吗?

【问题讨论】:

如果您不确定结果,请不要假设 X = Y 意味着 X 在所有情况下都是 Y。只需运行一些排列询问很多人,找到原始文档。在这里问已经是一个非常聪明的举动了:) 这就像 C、C#、Java 中的 "a != null" 与 "!(a == null)":没有逻辑上的区别。我敢打赌,如果性能上有任何可测量的差异,与顺序表扫描甚至从索引读取的成本相比,这将是微不足道的。 不同之处在于 Microsoft 已为 IS NOT 运算符申请了专利(在 VB.NET 的上下文中,即 SQL 拥有它之后的几年)。执行该专利的机会很大…… 【参考方案1】:

没有区别。

在我看来,在性能方面可能会有所不同。有人愿意详细说明吗?

所有主要引擎(即mysqlSQL ServerOraclePostgreSQL)都会在解析阶段合并这些谓词,并从中制定相同的计划。

处理这些条件比仅以一种或另一种顺序应用运算符更为复杂。

例如,在Oracle 中,IS NOT NULL(或NOT IS NULL)条件暗示使用索引的可能性,所以这样的查询:

SELECT  column
FROM    mytable
WHERE   column IS NOT NULL

很可能会使用index fast full scan 执行,而不会在运行时进行额外的检查(因为NULL 的值不会进入索引,所以检查它们是没有用的)。

即使需要检查每条记录,检查的顺序也将由优化器定义(而不是由谓词和运算符在WHERE 子句中出现的顺序)。

例如,这是一个Oracle 查询的计划:

SQL> EXPLAIN PLAN FOR
  2  
  2  SELECT *
  3  FROM   t_test
  4  WHERE  NOT column IS NULL
  5  /

Explained

SQL> SELECT  *
  2  FROM    TABLE(DBMS_XPLAN.display())
  3  /

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 958699830
----------------------------------------------------------------------------
| Id  | Operation         | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |        |    30 |  1260 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T_TEST |    30 |  1260 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("COLUMN" IS NOT NULL)

如您所见,filter 在内部被翻译成IS NOT NULLOracle 以及大多数评论者似乎认为这是更合适的形式)

更新:

正如 Jonathan Leffler 指出的那样,在评估元组(而不是单列)时,这些是不同的。

由混合的NULL 和非NULL 值组成的元组既不是NULL,也不是NOT NULL

PostgreSQL(支持这个针对元组的谓词)中,这两个表达式:

SELECT  (1, NULL) IS NULL
SELECT  (1, NULL) IS NOT NULL

评估为假。

【讨论】:

我同意IS NOT NULL 更具可读性。使用括号也更安全,因为它不会让你在你真正的意思是WHERE (type IS NOT NULL AND state = 1) or type = 2时不小心输入WHERE NOT (type IS NULL AND state = 1) or type = 2【参考方案2】:

在 LHS 项是简单变量或表达式的通常情况下,NOT x IS NULLx IS NOT NULL 之间没有区别。优化器会一视同仁地对待这两者。

但是,在完整的 SQL 中,LHS 术语不限于简单的变量或表达式;在形式语法中,LHS 是<row value predicand>

SQL/基础 - ISO/IEC 9075-2:2003

§8.7 <null predicate> (p395)

为空值指定一个测试。

<null predicate> ::= <row value predicand> <null predicate part 2>

<null predicate part 2> ::= IS [ NOT ] NULL

然后通过语法,你会发现:

§7.2 &lt;row value expression&gt; (p296)

指定行值。

[...]

<row value predicand>  ::=
       <row value special case>
 |     <row value constructor predicand>

<row value special case> ::= <nonparenthesized value expression primary> 

还有:

§7.1 &lt;row value constructor&gt; (p293)

指定要构造成行或部分行的值或值列表。

<row value constructor> ::=
       <common value expression>
 |     <boolean value expression>
 |     <explicit row value constructor>

[...]

<row value constructor predicand> ::=
       <common value expression>
 |     <boolean predicand>
 |     <explicit row value constructor>

就这样继续下去。 (通过 SQL 标准追逐任何东西都是一项艰巨的工作。您可以在 http://savage.net.au/SQL/ 找到该标准的高度超链接版本。)

但是,正如您可能从提到的“行值”中猜到的那样,您可以在 LHS 上组合多个简单的表达式来形成“行值构造函数谓词”。然后这两种形式是有区别的。

从概念上讲,您有:

(val1, val2, val3) IS NOT NULL

NOT (val1, val2, val3) IS NULL

现在,在第一种情况下,如果 val1、val2 和 val3 都不为 NULL,则为 TRUE。在第二种情况下,如果 val1、val2、val3 中的任何一个不为 NULL,则为 TRUE。因此,在某些情况下,这两个操作并不完全相同。

但是,正如我前面所说,对于简单列或表达式的通常情况,两者之间没有区别。

【讨论】:

好点,+1。实际上,它在PostgreSQL 中是这样工作的。 这是规范中的一般结构,它也适用于 RHS 端的其他运算符。例如,SELECT NOT true = ANY(ARRAY[false, false, true]);vs SELECT true &lt;&gt; ANY(ARRAY[false, false, true]);【参考方案3】:

IS NOT NULL 是comparison operator,就像IS NULL=&gt;&lt; 等。

NOT 是一个logical operator,作用于条件的其余部分。所以你可以说NOT type = 5NOT type IS NULL,甚至是NOT type IS NOT NULL

我的意思是指出,它们是两个非常不同的运算符,即使结果相同。当然,在布尔逻辑中,NOT (column IS NULL)column IS NOT NULL 之间没有区别,但知道区别是明智的。

至于性能,IS NOT NULL 可能会比NOT ... IS NULL 节省几个周期,因为您使用的是单个运算符而不是两个运算符,但是任何合理的优化器都会在查询运行之前发现它们是相同的。

【讨论】:

以上是关于“不为空”和“不为空”有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

oracle中nvl()函数有啥用啊?

检查字符串是不是不为空且不为空

提交后表单不为空字段

Oracle中查询某字段不为空的SQL语句怎么写

如何匹配不为空+不为空?

如何确保至少一个字段不为空?(如果只有一个不为空就可以)