Quando sp_executesql atualiza o plano de consulta?

13

Você precisará perdoar minha ingenuidade, pois não sou um DBA, mas meu entendimento é que, com o tempo, as estatísticas de um banco de dados são alteradas e um procedimento armazenado deve ser recompilado para manter o plano de consulta atualizado com as estatísticas mais recentes.

Supondo que eu tenha um procedimento armazenado no meu banco de dados que seja recompilado com as estatísticas mais recentes em algum intervalo regular, quais são as implicações de alinhar o procedimento armazenado no código e envolvê-lo em uma sp_executesqlinstrução? Perco a atualização do plano de consulta que costumava acontecer como parte da recompilação do procedimento?

Se houver mais alguma coisa (além de permissões) que eu precise considerar antes de fazer essa alteração, agradeceria suas idéias.

Eu li isso no MSDN:

A capacidade do otimizador de consulta do SQL Server para combinar a nova seqüência de caracteres Transact-SQL com um plano de execução existente é prejudicada pelas constantes alterações dos valores dos parâmetros no texto da seqüência, especialmente em instruções Transact-SQL complexas.

Portanto, supondo que o procedimento armazenado que estou tentando incorporar e envolver de sp_executesqlfato contenha alguns parâmetros, isso significa que, embora meu plano de execução seja armazenado em cache, estou dificultando a localização e a reutilização do SQL Server?

James Lewis
fonte

Respostas:

7

A linha do MSDN está falando sobre o uso EXEC(), assim:

SET @sql = 'SELECT foo FROM dbo.bar WHERE x = ''' + @x + ''';';
EXEC(@sql);

Nos meus testes, as versões modernas do SQL Server ainda podem reutilizar um plano como esse, mas pode haver outras variáveis ​​(como versão ou, por exemplo, se você adicionar WHEREcláusulas condicionais com base na presença de determinados parâmetros - nesse caso, irá gerar um plano diferente).

Se você usar sp_executesql, os valores dos parâmetros ainda poderão causar problemas de detecção (como no SQL normal), mas isso não tem nada a ver com o fato de o SQL Server poder reutilizar o plano. Esse plano será usado repetidamente, como se você não tivesse usado sp_executesql, a menos que variáveis ​​que causariam uma consulta direta sejam recompiladas; nesse caso, essa também será recompilada (essencialmente, o SQL Server não armazene qualquer coisa com o plano que diz "isso foi executado a partir do sp_executesql, mas este não foi):

SET @sql = N'SELECT foo FROM dbo.bar WHERE x = @x;';
EXEC sp_executesql @sql, N'@x VARCHAR(32)', @x;

Como um bônus, isso possui proteção interna contra SQL dinâmico e evita que você precise se preocupar em duplicar aspas simples devido a delimitadores de string. Eu escrevi sobre um pouco disso aqui .

Se você está tendo problemas com o plano de re-utilização e / ou parâmetro sniffing, algumas coisas que você deve olhar são OPTION (RECOMPILE), OPTIMIZE FOR, optimize for ad hoc workloadse simple/forced parameterization. Fiz algumas perguntas semelhantes em resposta a um webcast recente aqui, pode valer a pena:

http://sqlperformance.com/performance-palooza

A essência é: não tenha medo de usá-lo sp_executesql, mas use-o apenas quando necessário e gaste energia otimizando demais quando houver um problema real de desempenho. O exemplo acima é terrível, porque não há razão para usar SQL dinâmico aqui - escrevi esta resposta assumindo que você tem um caso de uso legítimo.

Aaron Bertrand
fonte
2

As consultas executadas via sp_executesql seguem as mesmas regras de planos de execução que as consultas normais que não são executadas através do sp_executesql. Se o texto da consulta for alterado, um novo plano será criado. Se o texto não for alterado devido ao usuário dos parâmetros, o plano será reutilizado. Quando as estatísticas são atualizadas, os planos expiram e novos planos são gerados na próxima vez que a consulta for executada.

mrdenny
fonte
Obrigado pela sua resposta, fiz uma edição sobre os parâmetros, pois agora percebi que, toda vez que chamo sp_ExecuteSql, usarei uma sequência diferente como consulta, devido ao fato de que, na perspectiva do Sql Server, substituí os parâmetros com valores codificados (eles serão inseridos no código antes de enviar minha consulta ao Sql Server). Você conhece uma maneira de contornar isso? Declarar variáveis ​​na minha instrução sql in-line ajudaria o otimizador de consultas a encontrar meu plano de consultas em cache?
James lewis