SQL Server 2012 e 2016 Padrão:
Se eu colocar if-else
lógica em um procedimento armazenado para executar uma das duas ramificações de código, dependendo do valor de um parâmetro, o mecanismo armazena em cache a versão mais recente?
E se na execução seguinte, o valor do parâmetro mudar, ele irá recompilar e refazer o cache do procedimento armazenado , já que uma ramificação diferente do código deve ser executada? (Esta consulta é bastante cara para compilar.)
Não, ele armazena em cache todas as versões. Ou melhor, ele armazena em cache uma versão com todos os caminhos explorados, compilados com o primeiro conjunto de variáveis passadas. A estimativa de cardinalidade para todos os planos será feita usando-os. Isso pode ser muito ruim se alguns valores passados forem NULL.
Aqui está uma demonstração rápida, usando o banco de dados Stack Overflow.
Crie um índice:
Crie um procedimento armazenado com uma dica de índice que aponta para um índice que não existe, em código ramificado.
Se eu executar esse proc armazenado procurando por Reputation = 1, recebo um erro.
Se corrigirmos o nome do índice e executarmos novamente a consulta, o plano em cache ficará assim:
Dentro, o XML terá duas referências à
@Reputation
variável.Um teste um pouco mais simples seria apenas obter um plano estimado para o proc armazenado. Você pode ver o otimizador explorando os dois caminhos:
Não, ele manterá o valor de tempo de execução da primeira compilação.
Se executarmos novamente com um diferente
@Reputation
:Do plano real :
Ainda temos um valor compilado de 1, mas agora um valor de tempo de execução de 2.
No cache do plano, que você pode conferir com uma ferramenta gratuita como a que minha empresa desenvolve, sp_BlitzCache :
O procedimento armazenado foi chamado duas vezes e cada instrução nele foi chamada uma vez.
O que temos então? Um plano em cache para ambas as consultas no procedimento armazenado.
Se você quiser esse tipo de lógica ramificada, precisará chamar procedimentos sub-armazenados:
Ou SQL dinâmico:
Espero que isto ajude!