Estou usando o SQL Server 2008 R2 e tenho esta pseudo consulta (SP):
select ...
from ...
WHERE @LinkMode IS NULL
AND (myColumn IN (...very long-running query...))
...
...
O problema é que a consulta demora muito para ser executada - mesmo que eu execute o SP com @LinkMode=2
.
Como você notou, a consulta de execução longa deve ser executada apenas se @LinkMode for nulo, o que não é o caso aqui. No meu caso @LinkMode = 2!
No entanto, se eu mudar para:
select ...
from ...
WHERE 1=2
AND (myColumn IN (...very long time exeted query...))
...
...
o SP corre rápido.
Já ouvi falar que às vezes o otimizador pode otimizar a ordem dos critérios.
Então eu pergunto :
Mesmo que o otimizador escolha uma rota diferente, o que pode ser mais rápido do que verificar se
=null
? Quero dizer, acho que verificarif a==null
é muito mais rápido do que executar a outra consulta longa ...Como posso forçar o SQL Server a executar a consulta conforme a escrevi (na mesma ordem)?
Você está caindo na armadilha da " consulta pega-tudo ", que é explicada muito bem por Gail Shaw aqui .
Para resumir o problema: o SQL Server otimiza a sobrecarga significativa da compilação de consulta, armazenando em cache um plano de consulta após a compilação e, posteriormente, verificando o cache em busca de um plano de consulta correspondente antes de uma compilação posterior. A "correspondência" que ocorre aqui é puramente textual, portanto, o valor real de uma variável não afetará isso.
Isso é bom 99% do tempo, mas em alguns casos é ruim . Um caso em que é ruim é quando alguém tenta construir uma cláusula WHERE como se fosse uma instrução IF em curto-circuito em C, etc. Isso não funciona bem, porque o compilador SQL precisa fazer um plano de consulta que funcionará independentemente do que os valores dos parâmetros realmente são, e a única maneira de lidar com essas condições de troca lógicas "inteligentes" na cláusula WHERE é fazer um plano simples de força bruta que apenas varre toda a tabela, filtrando as linhas à medida que avança , sem alavancar nenhum índice.
Não surpreendentemente, isso os torna uniformemente lentos, não importa quais sejam os valores dos parâmetros/variáveis.
Não há nenhuma maneira garantida de forçar o servidor SQL a executar as condições de sua cláusula em uma sequência específica. O otimizador sempre os avaliará na ordem que achar melhor.
O que você pode fazer é algo assim:
Se for uma opção, use uma instrução IF para executar a forma apropriada da consulta. Além disso, no SQL, você diz ao mecanismo de banco de dados o que fazer, não como fazer - as coisas não são executadas do começo ao fim. Pode ser difícil prever exatamente o que ele fará. Você provavelmente sabe disso ;)
O SQL dinâmico provavelmente funcionaria também, pois nesse caso o otimizador de consulta deve obter os valores reais em tempo de execução (corrija-me se estiver errado, na verdade não tenho certeza, mas parece que me lembro de usá-lo para situações semelhantes) . Mas estou com os outros neste, em que uma cláusula IF / ELSE serviria melhor para você, pois é a solução mais simples e fácil que fará exatamente o que é necessário.
Para referência futura, caso você ainda não o tenha usado, um site horrivelmente feio com um exemplo funcional para SQL dinâmico pode ser encontrado aqui, por exemplo: http://sqlusa.com/bestpractices/dynamicsql/
Eu recomendaria a construção IF/ELSE. Se, por qualquer motivo, isso não funcionar para você, você sempre pode considerar o uso da opção WITH RECOMPILE.