Первоначальный взгляд на планы выполнения показывает, что выражение 1/0
определено в операторах Compute Scalar:
Теперь, хотя планы выполнения начинают выполняться в крайнем левом положении, итеративно вызывая методы Open
и GetRow
методы дочерних итераторов для возврата результатов, SQL Server 2005 и более поздние версии содержат оптимизацию, в соответствии с которой выражения часто определяются только в Compute Scalar, причем оценка откладывается до следующего операция требует результата :
В этом случае результат выражения требуется только при сборке строки для возврата клиенту (о чем вы можете подумать, имея зеленый SELECT
значок). По этой логике отложенная оценка будет означать, что выражение никогда не вычисляется, поскольку ни один план не генерирует возвращаемую строку. Чтобы немного разобраться в этом, ни поиск по кластерному индексу, ни сканирование таблицы не возвращают строку, поэтому нет строки для сборки для возврата клиенту.
Однако существует отдельная оптимизация, при которой некоторые выражения могут быть определены как константы времени выполнения и, таким образом, оценены один раз перед началом выполнения запроса . В этом случае указание на то, что это произошло, можно найти в XML showplan (план поиска кластерного индекса слева, план сканирования таблицы справа):
Я написал больше о базовых механизмах и как они могут повлиять на производительность в этом блоге . Используя предоставленную там информацию, мы можем изменить первый запрос, чтобы оба выражения оценивались и кэшировались перед началом выполнения:
select 1/0 * CONVERT(integer, @@DBTS)
from #temp
where id = 1
select 1/0
from #temp2
where id = 1
Теперь первый план также содержит ссылку на постоянное выражение, и оба запроса выдают сообщение об ошибке. XML для первого запроса содержит:
Дополнительная информация: вычисление скаляров, выражений и производительности