В чем разница между "Не является нулевым" и "Не является нулевым",
SELECT id FROM customers WHERE type IS NOT Null;
Versus:
SELECT id FROM customers WHERE NOT type IS NULL;
Данные, возвращаемые одним из вышеперечисленных, будут точно такими же.
В чем разница и почему один из них предпочтительнее?
Edit:
Мне кажется, что может быть разница в производительности. Кто-нибудь позаботится об этом?
Ответы
Ответ 1
Нет никакой разницы.
Мне кажется, что может быть разница, когда дело доходит до производительности. Кто-нибудь позаботится об этом?
Все основные двигатели (т.е. MySQL
, SQL Server
, Oracle
и PostgreSQL
) объединит эти предикаты на этапе синтаксического анализа, сделав из них одинаковые планы.
Обработка этих условий более сложна, просто применяя операторы в том или ином порядке.
Например, в 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 NULL
(который Oracle
, как и большинство комментаторов, кажется, является более подходящей формой)
Update:
Как отметил Джонатан Леффлер, это разница при оценке кортежей (в отличие от отдельных столбцов).
Кортеж, состоящий из смешанных значений NULL
и non NULL
, не является ни a NULL
, ни a NOT NULL
.
В PostgreSQL
(который поддерживает этот предикат против кортежей), оба этих выражения:
SELECT (1, NULL) IS NULL
SELECT (1, NULL) IS NOT NULL
оценивается как false.
Ответ 2
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
, потому что вы используете один оператор вместо двух операторов, но любой разумный оптимизатор выяснит, что это то же самое, что и до запуска запроса.
Ответ 3
В обычном случае, когда член 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
И, преследуя грамматику, вы обнаружите, что:
§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>
и
§7.1 <row value constructor>
(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, чтобы сформировать "predicand конструктора значений строки". И тогда есть разница между двумя формами.
Концептуально у вас есть:
(val1, val2, val3) IS NOT NULL
против
NOT (val1, val2, val3) IS NULL
Теперь, в первом случае, вы получите TRUE, если каждый из val1, val2 и val3 не равен NULL. Во втором случае вы получите TRUE, если какой-либо из val1, val2, val3 не является NULL. Таким образом, существуют ситуации, когда две операции не идентичны.
Однако, как я уже говорил, для обычного случая простого столбца или выражения нет разницы между ними.