Por que o erro de consulta com resultado vazio é definido no SQL Server 2012?

31

Ao executar as seguintes consultas no MS SQL Server 2012, a segunda consulta falha, mas não a primeira. Além disso, quando executadas sem as cláusulas where, ambas as consultas falharão. Estou perplexo porque ambos falhariam, pois ambos deveriam ter conjuntos de resultados vazios. Qualquer ajuda / insight é apreciada.

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
DavidN
fonte

Respostas:

39

Uma visão inicial dos planos de execução mostra que a expressão 1/0é definida nos operadores Compute Scalar:

Planos gráficos

Agora, apesar de os planos de execução começarem a ser executados na extrema esquerda, chamando iterativamente Opene GetRowmétodos nos iteradores filhos para retornar resultados, o SQL Server 2005 e posteriores contêm uma otimização na qual as expressões geralmente são definidas apenas por um Escalar de computação, com a avaliação adiada para uma subseqüente operação requer o resultado :

Os operadores escalares de computação que aparecem nos planos de execução gerados pelo XML SET STATISTICS podem não conter o elemento RunTimeInformation.  Nos planos de apresentação gráficos, as linhas reais, as realizações reais e as realizações reais podem estar ausentes na janela Propriedades quando a opção Incluir plano de execução real estiver selecionada no SQL Server Management Studio.  Quando isso ocorre, significa que, embora esses operadores tenham sido usados ​​no plano de consulta compilado, seu trabalho foi realizado por outros operadores no plano de consulta em tempo de execução.  Observe também que o número de execuções na saída do Showplan gerado pelo SET STATISTICS PROFILE é equivalente à soma de religações e retrocessos nos Showplans gerados pelo SET STATISTICS XML.  De: MSDN Books Online

Nesse caso, o resultado da expressão é necessário apenas ao montar a linha para retornar ao cliente (que você pode pensar em ocorrer no SELECTícone verde ). Por essa lógica, a avaliação adiada significaria que a expressão nunca é avaliada porque nenhum plano gera uma linha de retorno. Para esclarecer um pouco o ponto, nem a Pesquisa de índice em cluster nem a Verificação de tabela retornam uma linha; portanto, não há linha a ser montada para retorno ao cliente.

No entanto, existe uma otimização separada, na qual algumas expressões podem ser identificadas como constantes de tempo de execução e avaliadas uma vez antes do início da execução da consulta . Nesse caso, uma indicação disso ocorreu pode ser encontrada no showplan XML (plano de busca de índice em cluster à esquerda, plano de varredura de tabela à direita):

Showplan XML

Escrevi mais sobre os mecanismos subjacentes e como eles podem afetar o desempenho nesta postagem do blog . Usando as informações fornecidas lá, podemos modificar a primeira consulta para que ambas as expressões sejam avaliadas e armazenadas em cache antes do início da execução:

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

select 1/0
from #temp2
where id = 1

Agora, o primeiro plano também contém uma referência de expressão constante e as duas consultas produzem a mensagem de erro. O XML para a primeira consulta contém:

Expressão constante

Mais informações: Escalares de computação, expressões e desempenho

Paul White diz que a GoFundMonica
fonte
21

Vou adivinhar de forma inteligente (e no processo provavelmente atrair um guru do SQL Server que pode dar uma resposta realmente detalhada).

A primeira consulta aborda a execução como:

  1. Digitalizar o índice da chave primária
  2. Procure os valores na tabela de dados necessários para a consulta

Ele escolhe esse caminho porque você possui uma wherecláusula na chave primária. Como nunca chega à segunda etapa, a consulta não falha.

O segundo não tem uma chave primária para executar, por isso aborda a consulta como:

  1. Faça uma varredura completa da tabela dos dados e recupere os valores necessários

Um desses valores está 1/0causando o problema.

Este é um exemplo do SQL Server otimizando a consulta. Para a maior parte, isso é uma coisa boa. O SQL Server moverá as condições da selectoperação de varredura de tabela. Isso geralmente salva etapas na avaliação da consulta.

Mas, essa otimização não é uma coisa boa sem mitigar. De fato, parece violar a documentação do SQL Server , que diz que a wherecláusula é avaliada antes da select. Bem, eles podem ter alguma explicação erudita para o que isso significa. Para a maioria dos humanos, porém, processar logicamente o whereantes do selectsignificaria (entre outras coisas) "não gera selecterros de cláusula nas linhas não retornadas ao usuário".

Gordon Linoff
fonte
1
Marque com +1 nenhuma pista se você estiver certo, mas a melhor resposta que posso ver é que a única diferença é a chave primária.
1
@GordonLinoff Paul Randal acaba de confirmar via Twitter que sua resposta foi positiva.
SchmitzIT
4
@ Ainda, a ordem real de execução, por mais diferente que seja, não deve levar a mensagens de erro como essa.
ypercubeᵀᴹ
7
@ypercube Erland Sommarskog concordaria com você (item do Connect)
Paul White disse que o GoFundMonica
2
Obrigado pelo ponteiro - eu entrei e votei de novo no pedido.
Gordon Linoff