Eu tenho uma instrução de exclusão que está usando um plano incorreto quando executado dentro de um procedimento armazenado, mas está escolhendo um plano muito melhor quando executado ad-hoc.
Eu reconstruí todos os índices das tabelas usadas pela consulta e eliminei todos os caches. O otimizador ainda escolhe o plano errado para o procedimento armazenado.
Gostaria de saber por que o otimizador está usando um plano de execução diferente para o procedimento armazenado versus o SQL ad-hoc.
ATUALIZAÇÃO: Eu acho que deve ter sido os parâmetros, afinal - quando eu executei o código ad-hoc com a variável codificada, posso obter o plano "ruim" com o valor certo (é uma data, valores com um ano de idade parecem gerar o plano "bom"). Agora, tente forçar o plano "bom" no proc usando uma dica de consulta.
SOLUÇÃO: Acabei obtendo o plano desejado usando a dica OPTIMIZE FOR UNKNOWN.
fonte
WHERE
cláusula?Respostas:
Suspeitos comuns:
Ponto 1: o otimizador pode escolher o melhor plano para as constantes.
Mude as constantes = mude o plano. Uma plenária parametrizada é recuperável
O ponto 2 introduzirá conversões implícitas devido à precedência do tipo de dados,
por exemplo, coluna varchar em comparação com o parâmetro nvarchar
Ponto 3: use mascaramento de parâmetro ou OPTIMIZE FOR UNKNOWN
Edit: Para testar: execute proc armazenado, execute sp_updatestats, execute novamente. Isso invalidará os planos em cache, o que é melhor do que limpar o cache do plano
Edit: após o comentário de jcolebrand
Você pode desativar o sniffing de várias maneiras. Os 3 principais são
Máscara de parâmetro:
O mascaramento e a dica OPTIMIZE têm o mesmo efeito (talvez por razões diferentes). Ou seja, o otimizador precisa usar estatísticas e distribuição de dados ( Nota: ainda em teste por Mark Storey-Smith )
avaliar os parâmetros por seus próprios méritos ?, e não como eles foram a última chamada. O otimizador pode recompilar ou não. O SQL Server 2005 adicionou a recompilação no nível da instrução para que houvesse menos impactoAgora, por que um plano com parâmetros "sniffed" é "pegajoso" comparado a parâmetros mascarados / "desconhecidos", não tenho certeza.
Eu uso o mascaramento de parâmetros desde o SQL Server 2000 para todos, exceto o código mais simples. Observei que é provável que isso aconteça com código mais complexo. E no meu antigo emprego, tenho alguns procedimentos de relatório que podem alterar os padrões dos parâmetros do plano. Eu acho que a abordagem do "culto à carga" foi mais fácil do que uma ligação de suporte.
Edit 2, 12 Out 2011, depois de algum bate-papo
O mascaramento de parâmetro e OPTIMIZE FOR UNKNOWN têm o mesmo efeito, pelo que sei.
A dica é mais limpa do que o mascaramento, mas foi adicionada ao SQL Server 2008.
A detecção de parâmetros ocorre no momento da compilação.
WITH RECOMPILE gera um novo plano a cada execução. Isso significa que uma má escolha de padrões influenciará o plano. No meu último trabalho, pude demonstrar isso facilmente com algum código de relatório: a alteração dos padrões dos parâmetros alterou o plano, independentemente dos parâmetros fornecidos.
Este artigo do MS Connect é interessante: Uso de índice abaixo do ideal no procedimento armazenado (mencionado em uma das respostas de SO abaixo)
Questões pendentes
O sniffing ainda se aplica a WITH RECOMPILE? Ou seja, se o otimizador souber descartar o plano, ele pretende reutilizá-lo?
Por que os planos sniffed são "pegajosos"?
Links de SO:
https://stackoverflow.com/q/272726/27535
Remus Rusanu (equipe MS SQL) e eu tivemos uma briga aqui no SO
fonte
OPTION (RECOMPILE)
ou todo o processoWITH RECOMPILE
para forçar o SQL Server a desconsiderar os planos existentes.OPTIMIZE
porque a Microsoft é uma empresa americana. :)Não esqueça que as configurações ANSI que você definiu para a conexão planejam uma função na seleção do plano de execução. Quando o aplicativo chama o procedimento armazenado, provavelmente possui configurações ANSI diferentes da sua conexão SSMS.
fonte