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

?

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 ".


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.


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.


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: @


-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)

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.