Оборачивает ли обнуляемые столбцы в ISNULL сканирование таблицы? - PullRequest
11 голосов
/ 19 сентября 2011

Правило анализа кода SR0007 для проектов баз данных Visual Studio 2010 гласит:

Вы должны явно указать, как обрабатывать значения NULL в выражениях сравнения, оборачивая каждый столбец, который может содержать значение NULL, в функцию ISNULL.

Однако правило анализа кода SR0006 нарушается, когда:

Как часть сравнения, выражение содержит ссылку на столбец ... Ваш код может вызвать сканирование таблицы, если он сравнивает выражение, содержащее ссылку на столбец.

Применимо ли это к ISNULL или ISNULL никогда не приводит к сканированию таблицы?

1 Ответ

18 голосов
/ 19 сентября 2011

Да, это вызывает сканирование таблицы. (хотя, кажется, оптимизируется, если столбец на самом деле не обнуляемый)

Правило SR0007 является крайне плохим общим советом, поскольку оно делает предикат неосуществимым и означает, что любые индексы в столбце будут бесполезны. Даже если в столбце нет индекса, это может привести к неточным оценкам количества элементов, влияющим на другие части плана.

Классификация его в категории Microsoft.Performance довольно забавна, так как кажется, что она написана кем-то, не понимающим производительность запросов.

Он утверждает, что обоснование

Если ваш код сравнивает два значения NULL или значение NULL с любым другим значение, ваш код будет возвращать неизвестный результат.

Хотя само выражение оценивается как unknown, ваш код возвращает полностью детерминированный результат, как только вы поймете, что любое =, <>, >, < и т. Д. При сравнении с NULL оценивается как Unknown и что предложение WHERE возвращает только те строки, в которых выражение оценивается как true.

Возможно, они означают, что ANSI_NULLS выключен, но пример, который они приводят в документации WHERE ISNULL([c2],0) > 2; против WHERE [c2] > 2;, в любом случае не будет затронут этой настройкой. Эта настройка

влияет на сравнение, только если один из операндов сравнения либо переменная со значением NULL, либо с литералом NULL.

Планы выполнения, показывающие сканы против поиска или ниже

CREATE TABLE #foo
  (
     x INT NULL UNIQUE
  )

INSERT INTO #foo
SELECT ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM   sys.all_columns

SELECT *
FROM   #foo
WHERE  ISNULL(x, 10) = 10

SELECT *
FROM   #foo
WHERE  x = 10

SELECT *
FROM   #foo
WHERE  x = 10
        OR x IS NULL 

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...