Почему ошибка запроса с пустым набором результатов в SQL Server 2012?


31

При выполнении следующих запросов в MS SQL Server 2012 второй запрос не выполняется, но не первый. Кроме того, при запуске без предложений where оба запроса не будут выполнены. Я в недоумении, почему любой из них потерпит неудачу, так как оба должны иметь пустые наборы результатов. Любая помощь / понимание приветствуется.

create table #temp
(id     int primary key)

create table #temp2
(id     int)

select 1/0
from #temp
where id = 1

select 1/0
from #temp2
where id = 1

Ответы:


39

Первоначальный взгляд на планы выполнения показывает, что выражение 1/0определено в операторах Compute Scalar:

Графические планы

Теперь, хотя планы выполнения начинают выполняться в крайнем левом положении, итеративно вызывая методы Openи GetRowметоды дочерних итераторов для возврата результатов, SQL Server 2005 и более поздние версии содержат оптимизацию, в соответствии с которой выражения часто определяются только в Compute Scalar, причем оценка откладывается до следующего операция требует результата :

Скалярные операторы вычисления, которые появляются в Showplans, сгенерированных SET STATISTICS XML, могут не содержать элемент RunTimeInformation.  В графических Showplans фактические строки, фактические повторные привязки и фактические перемотки могут отсутствовать в окне свойств, если в SQL Server Management Studio выбран параметр «Включить фактический план выполнения».  Когда это происходит, это означает, что хотя эти операторы использовались в скомпилированном плане запросов, их работа выполнялась другими операторами в плане запросов во время выполнения.  Также обратите внимание, что число выполнений в выходных данных Showplan, сгенерированных SET STATISTICS PROFILE, эквивалентно сумме повторных и перемоток в Showplans, сгенерированных SET STATISTICS XML.  От: MSDN Books Online

В этом случае результат выражения требуется только при сборке строки для возврата клиенту (о чем вы можете подумать, имея зеленый SELECTзначок). По этой логике отложенная оценка будет означать, что выражение никогда не вычисляется, поскольку ни один план не генерирует возвращаемую строку. Чтобы немного разобраться в этом, ни поиск по кластерному индексу, ни сканирование таблицы не возвращают строку, поэтому нет строки для сборки для возврата клиенту.

Однако существует отдельная оптимизация, при которой некоторые выражения могут быть определены как константы времени выполнения и, таким образом, оценены один раз перед началом выполнения запроса . В этом случае указание на то, что это произошло, можно найти в XML showplan (план поиска кластерного индекса слева, план сканирования таблицы справа):

Showplan XML

Я написал больше о базовых механизмах и как они могут повлиять на производительность в этом блоге . Используя предоставленную там информацию, мы можем изменить первый запрос, чтобы оба выражения оценивались и кэшировались перед началом выполнения:

select 1/0 * CONVERT(integer, @@DBTS)
from #temp
where id = 1

select 1/0
from #temp2
where id = 1

Теперь первый план также содержит ссылку на постоянное выражение, и оба запроса выдают сообщение об ошибке. XML для первого запроса содержит:

Постоянное выражение

Дополнительная информация: вычисление скаляров, выражений и производительности


21

Я собираюсь догадаться (и в процессе, вероятно, привлеку гуру SQL Server, который может дать действительно подробный ответ).

Первый запрос приближается к выполнению следующим образом:

  1. Сканирование индекса первичного ключа
  2. Посмотрите значения в таблице данных, необходимые для запроса

Он выбирает этот путь, потому что у вас есть whereпредложение по первичному ключу. Он никогда не дойдет до второго шага, поэтому запрос не завершится неудачей.

Второй не имеет первичного ключа для запуска, поэтому он подходит к запросу так:

  1. Проведите полное сканирование таблицы данных и получите необходимые значения

Одно из этих значений 1/0вызывает проблему.

Это пример SQL Server, оптимизирующего запрос. По большей части это хорошая вещь. SQL Server переместит условия из selectоперации сканирования таблицы. Это часто экономит шаги в оценке запроса.

Но эта оптимизация не является хорошей вещью. Фактически, это, кажется, нарушает саму документацию по SQL Server , в которой говорится, что whereпредложение оценивается до select. Ну, у них может быть какое-то эрудированное объяснение того, что это значит. Однако для большинства людей логическая обработка значения wherebefore selectозначает (среди прочего) «не генерировать selectошибки -clause для строк, не возвращаемых пользователю».


1
+1 без понятия, если вы правы, но лучший ответ, который я вижу, с той лишь разницей, что это первичный ключ.

1
@GordonLinoff Пол Рэндал только что подтвердил в Твиттере, что твой ответ ударил.
SchmitzIT

4
@ Тем не менее, фактический порядок выполнения, как бы он ни отличался, не должен приводить к таким сообщениям об ошибках.
ypercubeᵀᴹ

7
@ypercube Эрланд Соммарског согласился бы с вами (Соединить предмет)
Пол Уайт говорит, что GoFundMonica

2
Спасибо за указатель - я вошел в систему и проголосовал за запрос.
Гордон Линофф
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.