Tenho duas consultas quase idênticas em execução na mesma instância do SQL Server 2005:
- A primeira é a
SELECT
consulta original gerada pelo LINQ (eu sei, eu sei... não sou o desenvolvedor do aplicativo, apenas o DBA :). - O segundo é exatamente igual ao primeiro, acrescido de um
OPTION (RECOMPILE)
no final.
Nada mais foi alterado.
O primeiro leva 55 segundos toda vez que é executado.
O segundo leva 2 segundos.
Ambos os conjuntos de resultados são idênticos.
Por que essa dica geraria um ganho tão dramático no desempenho?
A entrada do Books Online em RECOMPILE
não oferece uma explicação muito detalhada:
Instrui o SQL Server Database Engine a descartar o plano gerado para a consulta após sua execução, forçando o otimizador de consulta a recompilar um plano de consulta na próxima vez que a mesma consulta for executada. Sem especificar RECOMPILE, o Mecanismo de Banco de Dados armazena em cache os planos de consulta e os reutiliza. Ao compilar planos de consulta, a dica de consulta RECOMPILE usa os valores atuais de quaisquer variáveis locais na consulta e, se a consulta estiver dentro de um procedimento armazenado, os valores atuais passados para quaisquer parâmetros.
RECOMPILE é uma alternativa útil para criar um procedimento armazenado que usa a cláusula WITH RECOMPILE quando apenas um subconjunto de consultas dentro do procedimento armazenado, em vez de todo o procedimento armazenado, deve ser recompilado. Para obter mais informações, consulte Recompilando procedimentos armazenados. RECOMPILE também é útil quando você cria guias de plano. Para obter mais informações, consulte Otimizando consultas em aplicativos implantados usando guias de plano.
Como minha consulta tem muitas variáveis locais, meu palpite é que o SQL Server é capaz de otimizá-la (sério) quando uso a OPTION (RECOMPILE)
dica de consulta.
Onde quer que eu olhe, as pessoas estão dizendo que isso OPTION (RECOMPILE)
deve ser evitado. A explicação para isso geralmente é que, usando essa dica, o SQL Server não é capaz de reutilizar esse plano de execução e, portanto, precisa perder tempo recompilando-o sempre.
(Mas) Dada a gigantesca vantagem de desempenho, estou inclinado a pensar que usar essa dica de consulta desta vez seria uma coisa boa.
Devo usá-lo? Se não, existe uma maneira de forçar o SQL Server a usar um plano de execução melhor sem essa dica e sem alterar o aplicativo?
Conforme documentado no artigo Estatísticas usadas pelo otimizador de consultas no Microsoft SQL Server 2005
Quando o otimizador não tiver nenhuma estatística utilizável para uma coluna, ele adivinhará que um
=
predicado corresponderá a 10% das linhas,BETWEEN
9% e qualquer uma delas>, >=, < and <=
corresponderá a 30%. Se houver estatísticas de coluna disponíveis, um=
predicado será tratado de forma diferente conforme abaixo.Portanto, isso é essencialmente o mesmo que usar for
OPTIMIZE FOR (UNKNOWN)
. Pode muito bem ser mais preciso do que um10%
palpite simples, mas não é adaptado aos valores específicos que você está consultando.Com o uso de
RECOMPILE
você provavelmente está obtendo estimativas de cardinalidade mais precisas e, portanto, um plano diferente com pedidos de junção/tipos de junção mais adequados ao número de linhas retornadas de diferentes partes de sua consulta real.