SQL dynamique - EXEC (@SQL) contre EXEC SP_EXECUTESQL (@SQL)

95

Quels sont les avantages et les inconvénients réels de l'exécution d'une commande SQL dynamique dans une procédure stockée dans SQL Server à l'aide de

EXEC (@SQL)

contre

EXEC SP_EXECUTESQL @SQL

?

Machine à cendre
la source

Réponses:

96

sp_executesqlest plus susceptible de promouvoir la réutilisation du plan de requête. Lors de l'utilisation sp_executesql, les paramètres sont explicitement identifiés dans la signature d'appel. Cet excellent article décrit ce processus .

La référence souvent citée pour de nombreux aspects de SQL dynamique est la lecture incontournable d'Erland Sommarskog: " The Curse and Blessings of Dynamic SQL ".

Blé Mitch
la source
21

Le grand avantage de SP_EXECUTESQL est qu'il vous permet de créer des requêtes paramétrées, ce qui est très bien si vous vous souciez de l'injection SQL.

DJ.
la source
1
Je ne pense pas que vous puissiez paramétrer un SQL dynamique sans cela ??
DJ.
EXEC ('SELECT * FROM FOO WHERE ID =?', 123) remplacera l'espace réservé du paramètre "?" avec la valeur 123, puis exécutez la requête, en retournant un résultat pour SELECT * FROM FOO WHERE ID = 123
Peter Wone
1
Oups, cette syntaxe n'est disponible que pour les serveurs liés.
Peter Wone le
1
Absolument l'une des principales raisons d'utiliser sp_executesql si vous construisez la requête de manière dynamique pour empêcher l'injection SQL.
Steven Rogers
5

L' article de Microsoft Utilisation de sp_executesql recommande d'utiliser sp_executesqlau lieu de l' executeinstruction.

Étant donné que cette procédure stockée prend en charge la substitution de paramètres , sp_executesql est plus polyvalent que EXECUTE; et comme sp_executesql génère des plans d'exécution qui sont plus susceptibles d'être réutilisés par SQL Server, sp_executesql est plus efficace que EXECUTE.

Donc, à emporter: n'utilisez pas de executedéclaration . Utilisez sp_executesql.

Gan
la source
7
Votre plat à emporter ne tient pas toujours. Il y a des occasions où il n'y a pas de bonus d'efficacité en utilisant sp_executesql, mais vous pouvez protéger votre code contre les attaques par injection SQL. Parfois, vous ne pouvez tout simplement pas utiliser sp_executesql comme vous pouvez utiliser exec, alors ... quelqu'un a dit - il n'y a pas de solution miracle. Je suis d'accord.
OzrenTkalcecKrznaric
Oui, Microsoft aurait dû le dire comme "plus susceptible d'être efficace". Et étant dans l'industrie depuis quelques années, j'ai vu des cas où sp_executesqlne peut pas être utilisé pour remplacer execute. Peut-être devrais-je mettre le point que j'essaie de souligner comme suit: utiliser sp_executesqlau lieu de execute autant que possible .
Gan
2

J'utiliserais toujours sp_executesql ces jours-ci, tout ce que c'est vraiment est un wrapper pour EXEC qui gère les paramètres et les variables.

Cependant, n'oubliez pas OPTION RECOMPILE lors du réglage des requêtes sur des bases de données très volumineuses, en particulier lorsque vous avez des données réparties sur plusieurs bases de données et que vous utilisez une contrainte pour limiter les analyses d'index.

À moins que vous n'utilisiez OPTION RECOMPILE, le serveur SQL tentera de créer un plan d'exécution «taille unique» pour votre requête et exécutera une analyse complète de l'index à chaque exécution.

Ceci est beaucoup moins efficace qu'une recherche et signifie qu'il analyse potentiellement des index entiers qui sont contraints à des plages que vous n'interrogez même pas: @

Ten98
la source
-2
  1. Déclarez la variable
  2. Définissez-le par votre commande et ajoutez des parties dynamiques comme utiliser les valeurs des paramètres de sp (ici @IsMonday et @IsTuesday sont des paramètres de sp)
  3. exécuter la commande

    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
la source
15
Ceci est ouvert à l'injection SQL, si vous mettez par exemple "a '; DROP DATABASE DATABASE_NAME; GO;';" dans la variable @IsMonday
Erik A. Brandstadmoen
est-il sujet à une injonction SQL si @IsMonday est un entier?
Vikas Rana
@VikasRana @IsMonday ne peut pas être inten SQL dynamique. Notez que @sql est déclaré comme varcharounvarchar
Weihui Guo