"Is Not Null"和"Not Is Null"之间的区别是什么?

Ico*_*ood 27 mysql sql sql-server

SELECT id FROM customers WHERE type IS NOT Null;
Run Code Online (Sandbox Code Playgroud)

与:

SELECT id FROM customers WHERE NOT type IS NULL;
Run Code Online (Sandbox Code Playgroud)

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

有什么区别,为什么其中一个会更好?

编辑:
在我看来,在性能方面可能会有所不同.有人关心这个吗?

Qua*_*noi 32

没有区别.

在我看来,在性能方面可能会有所不同.有人关心这个吗?

所有主要搜索引擎(即MySQL,SQL Server,OraclePostgreSQL)将合并在分析阶段,从他们制作计划相同,这些谓词.

处理这些条件比仅仅按一个或另一个顺序应用操作员更复杂.

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

SELECT  column
FROM    mytable
WHERE   column IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

很可能会用a执行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)
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,它filter被内部翻译成了一个IS NOT NULL(Oracle与大多数评论者一起似乎认为是更合适的形式)

更新:

正如乔纳森·莱弗勒所指出的那样,这些在评估元组时是不同的(而不是单列).

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

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

SELECT  (1, NULL) IS NULL
SELECT  (1, NULL) IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

评价为假.

  • 我同意`IS NOT NULL`更具可读性.使用括号也更安全,因为它实际上意味着`WHERE(类型IS NOT NULL AND state = 1)或类型时不会让你不小心输入`WHERE NOT(类型IS NULL AND state = 1)或type = 2` = 2` (2认同)

wup*_*tah 16

IS NOT NULL比较操作符,就像IS NULL=,>,<等.

NOT是一个逻辑运算符,作用于其余条件.所以你可以说NOT type = 5,NOT type IS NULL甚至是NOT type IS NOT NULL.

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

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


Jon*_*ler 12

在LHS术语是简单变量或表达式的通常情况下,NOT x IS NULL和之间没有区别x IS NOT NULL.优化器将对两者进行相同的处理.

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

SQL/Foundation - 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
Run Code Online (Sandbox Code Playgroud)

通过语法追逐,您会发现:

§7.2 <row value expression>(p296)

指定行值.

[...]

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

<row value special case> ::= <nonparenthesized value expression primary> 
Run Code Online (Sandbox Code Playgroud)

和:

§7.1 <row value constructor>(p293)

指定要构造为行或部分行的值或值列表.

<row value constructor> ::=
       <common value expression>
 |     <boolean value expression>
 |     <explicit row value constructor>
Run Code Online (Sandbox Code Playgroud)

[...]

<row value constructor predicand> ::=
       <common value expression>
 |     <boolean predicand>
 |     <explicit row value constructor>
Run Code Online (Sandbox Code Playgroud)

所以它继续.(通过SQL标准追逐任何东西都是很难的.你可以在http://savage.net.au/SQL/找到一个高度超链接的标准版本.)

但是,正如您可能从提到的"行值"中猜到的那样,您可以在LHS上组合多个简单表达式以形成"行值构造函数谓词".然后两种形式之间存在差异.

从概念上讲,你有:

(val1, val2, val3) IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

VS

NOT (val1, val2, val3) IS NULL
Run Code Online (Sandbox Code Playgroud)

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

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