SQL dinâmico - EXEC (@SQL) versus EXEC SP_EXECUTESQL (@SQL)

95

Quais são os prós e contras do mundo real de executar um comando SQL dinâmico em um procedimento armazenado no SQL Server usando

EXEC (@SQL)

versus

EXEC SP_EXECUTESQL @SQL

?

Ash Machine
fonte

Respostas:

96

sp_executesqlé mais provável que promova a reutilização do plano de consulta. Ao usar sp_executesql, os parâmetros são identificados explicitamente na assinatura de chamada. Este excelente artigo descreve esse processo .

A referência freqüentemente citada para muitos aspectos do sql dinâmico é a leitura obrigatória de Erland Sommarskog: " The Curse and Blessings of Dynamic SQL ".

Trigo mitch
fonte
21

A grande vantagem do SP_EXECUTESQL é que ele permite que você crie consultas parametrizadas, o que é muito bom se você se preocupa com injeção de SQL.

DJ.
fonte
1
Eu não acho que você pode parameteizar um sql dinâmico sem ele ??
DJ.
EXEC ('SELECT * FROM FOO WHERE ID =?', 123) substituirá o marcador de posição do parâmetro "?" com o valor 123 e, em seguida, execute a consulta, retornando um resultado para SELECT * FROM FOO WHERE ID = 123
Peter Wone
1
Ops, essa sintaxe está disponível apenas para servidores vinculados.
Peter Wone
1
Com certeza um dos maiores motivos para usar sp_executesql se estiver criando a consulta dinamicamente para evitar injeção de sql.
Steven Rogers,
5

O artigo Usando sp_executesql da Microsoft recomenda o uso em sp_executesqlvez da executeinstrução.

Como esse procedimento armazenado oferece suporte à substituição de parâmetro , sp_executesql é mais versátil que EXECUTE; e como sp_executesql gera planos de execução com maior probabilidade de serem reutilizados pelo SQL Server, sp_executesql é mais eficiente que EXECUTE.

Portanto, a conclusão: Não use executedeclaração . Use sp_executesql.

Gan
fonte
7
Seu takeaway nem sempre é válido. Há ocasiões em que não há bônus de eficiência usando sp_executesql, mas você pode proteger seu código do ataque de injeção de sql. Às vezes você simplesmente não pode usar sp_executesql da mesma forma que usa exec, então ... alguém disse - não há solução mágica. Concordo.
OzrenTkalcecKrznaric
Sim, a Microsoft deveria ter colocado isso como "mais provável de ser eficiente". E estando na indústria há alguns anos, tenho visto casos em sp_executesqlque não pode ser usado para substituir execute. Talvez eu deva colocar o ponto que estou tentando enfatizar como: Use em sp_executesqlvez de execute sempre que possível .
Gan de
2

Eu sempre usaria sp_executesql atualmente, tudo o que realmente é é um invólucro para EXEC que lida com parâmetros e variáveis.

No entanto, não se esqueça de OPTION RECOMPILE ao ajustar consultas em bancos de dados muito grandes, especialmente quando você tiver dados estendidos por mais de um banco de dados e estiver usando CONSTRAINT para limitar as varreduras de índice.

A menos que você use OPTION RECOMPILE, o SQL server tentará criar um plano de execução "tamanho único" para sua consulta e executará uma varredura completa do índice cada vez que for executado.

Isso é muito menos eficiente do que uma busca e significa que está potencialmente verificando índices inteiros que são restritos a intervalos que você nem mesmo está consultando: @

Ten98
fonte
-2
  1. Declare a variável
  2. Defina-o pelo seu comando e adicione partes dinâmicas como valores de parâmetro de uso de sp (aqui @IsMonday e @IsT dezenas são parâmetros de sp)
  3. execute o comando

    declare  @sql varchar (100)
    set @sql ='select * from #td1'
    
    if (@IsMonday+@IsTuesday !='')
    begin
    set @sql= @sql+' where PickupDay in ('''+@IsMonday+''','''+@IsTuesday+''' )'
    end
    exec( @sql)
Sara
fonte
15
Está aberto para injeção SQL, se você colocar, por exemplo, "a '; DROP DATABASE DATABASE_NAME; GO;';" na variável @IsMonday
Erik A. Brandstadmoen
está sujeito a injeção de sql se @IsMonday estiver int?
Vikas Rana
@VikasRana @IsMonday não pode estar intem SQL dinâmico. Observe que @sql é declarado como varcharounvarchar
Weihui Guo