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. Não sei por que qualquer um deles falharia, já que 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
Uma olhada inicial nos planos de execução mostra que a expressão
1/0
é definida nos operadores Compute Scalar:Agora, embora os planos de execução comecem a ser executados na extrema esquerda, chamando iterativamente
Open
eGetRow
métodos em iteradores filhos para retornar resultados, o SQL Server 2005 e posterior contém uma otimização em que as expressões geralmente são definidas apenas por um Compute Scalar, com avaliação adiada até um próximo operação requer o resultado :Neste caso, o resultado da expressão só é necessário na hora de montar a linha para retorno ao cliente (o que você pode imaginar que ocorre no
SELECT
ícone verde). Por essa lógica, a avaliação adiada significaria que a expressão nunca é avaliada porque nenhum dos planos gera uma linha de retorno. Para trabalhar um pouco o ponto, nem o Clustered Index Seek nem o Table Scan retornam uma linha, então não há nenhuma linha para montar para retornar ao cliente.No entanto, há uma otimização separada em que algumas expressões podem ser identificadas como constantes de tempo de execução e, portanto, avaliadas uma vez antes do início da execução da consulta .
Neste caso*, uma indicação de que isso ocorreu pode ser encontrada no showplan XML (plano Clustered Index Seek à esquerda, plano Table Scan à direita):
Escrevi mais sobre os mecanismos subjacentes e como eles podem afetar o desempenho neste post de 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:
Agora, o primeiro plano também contém uma referência de expressão constante e ambas as consultas produzem a mensagem de erro. O XML para a primeira consulta contém:
Mais informações: escalares de computação, expressões e desempenho
Um exemplo em que um erro é relatado devido ao cache constante de tempo de execução, mas não há indicação no plano de execução (gráfico ou XML):
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:
Ele escolhe esse caminho porque você tem uma
where
cláusula na chave primária. Ele nunca chega à segunda etapa, portanto, a consulta não falha.O segundo não possui uma chave primária para ser executado, portanto aborda a consulta como:
Um desses valores está
1/0
causando o problema.Este é um exemplo de SQL Server otimizando a consulta. Na maioria das vezes, isso é uma coisa boa. O SQL Server moverá as condições da
select
operação de verificação da tabela. Isso geralmente economiza etapas na avaliação da consulta.Mas essa otimização não é uma coisa boa absoluta. Na verdade, parece violar a própria documentação do SQL Server , que diz que a
where
cláusula é avaliada antes doselect
. Bem, eles podem ter alguma explicação erudita para o que isso significa. Para a maioria dos humanos, no entanto, processar logicamente owhere
antes doselect
significaria (entre outras coisas) "não gerarselect
erros -cláusula em linhas não retornadas ao usuário".