Forçar o SQL Server a executar as condições de consulta conforme gravadas?


14

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 leva muito tempo para ser executada - mesmo que eu execute o SP com @LinkMode=2.

Como você notou, a consulta de longa execução 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 não correr rápido.

Ouvi dizer 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 a verificação if a==nullé muito mais rápida do que executar a outra consulta longa ...

  • Como forçar o SQL Server a executar a consulta conforme a escrevi (na mesma ordem)?

Respostas:


22

Você está caindo na armadilha " Catch-All Query ", que é explicada muito bem por Gail Shaw aqui .

Para resumir o problema: O SQL Server otimiza a sobrecarga significativa da compilação de consultas, 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 C de curto-circuito etc. Isso não funciona bem, porque o compilador SQL precisa fazer um plano de consulta que funcione independentemente do que realmente são os valores dos parâmetros e a única maneira de lidar com essas condições de comutação lógicas "inteligentes" na cláusula WHERE é fazer um plano simples de força bruta que apenas varre a tabela inteira, filtrando as linhas à medida que avançam , sem alavancar nenhum índice.

Não surpreendentemente, isso os torna uniformemente lentos, independentemente dos valores dos parâmetros / variáveis.


8

Não há maneira garantida de forçar o SQL Server a executar suas condições de cláusula em uma sequência específica. O otimizador sempre os avaliará na ordem que achar melhor.

O que você pode fazer é algo como isto:

IF @LinkMode IS NULL
BEGIN
    select ...
    from ...
    WHERE (myColumn IN (...very long time exeted query...))
         ...
         ...
END
ELSE
BEGIN
    select ...
    from ...
    WHERE ...
         ...
END

3

Se for uma opção, use uma instrução SE 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 fazê-lo - as coisas não são executadas do começo ao fim. Pode ser difícil prever o que exatamente ele fará. Você provavelmente já sabe disso;)


2

O SQL dinâmico provavelmente também funcionaria, pois nesse caso o otimizador de consulta deve obter os valores reais em tempo de execução (me corrija se estiver errado, na verdade não tenho certeza, mas pareço lembrar de usá-lo para situações semelhantes) . Mas estou com os outros neste, em que uma cláusula IF / ELSE seria melhor para você, pois é a solução mais simples e fácil que fará exatamente o necessário.

Para referência futura, caso você ainda não o tenha usado, um site horrivelmente feio com um exemplo funcional de SQL dinâmico pode ser encontrado aqui, por exemplo: http://sqlusa.com/bestpractices/dynamicsql/


1

Eu recomendaria a construção IF / ELSE. Se, por qualquer motivo que não funcionar, você sempre poderá usar a opção WITH RECOMPILE.


Você poderia elaborar como seria a "construção if / else"? : D
jcolebrand

Eu sugeriria usar OPTION (WITH RECOMPILE), pois isso geraria um plano ideal a cada vez - o atraso da compilação aumentaria a sobrecarga, mas suspeito que seja melhor no geral neste caso.
SqlRyan
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.