Dynamisches SQL - EXEC (@SQL) versus EXEC SP_EXECUTESQL (@SQL)

95

Was sind die Vor- und Nachteile der realen Welt bei der Ausführung eines dynamischen SQL-Befehls in einer gespeicherten Prozedur in SQL Server?

EXEC (@SQL)

gegen

EXEC SP_EXECUTESQL @SQL

?

Aschemaschine
quelle

Antworten:

96

sp_executesqlfördert eher die Wiederverwendung von Abfrageplänen. Bei der Verwendung sp_executesqlwerden Parameter in der aufrufenden Signatur explizit angegeben. Dieser ausgezeichnete Artikel beschreibt diesen Prozess .

Die oft zitierte Referenz für viele Aspekte von dynamischem SQL ist Erland Sommarskogs Muss: " Der Fluch und der Segen von dynamischem SQL ".

Mitch Wheat
quelle
21

Das Besondere an SP_EXECUTESQL ist, dass Sie damit parametrisierte Abfragen erstellen können. Dies ist sehr gut, wenn Sie sich für die SQL-Injection interessieren.

DJ.
quelle
1
Ich glaube nicht, dass Sie ein dynamisches SQL ohne es parametrisieren können?
DJ.
EXEC ('SELECT * FROM FOO WHERE ID =?', 123) ersetzt den Parameterplatzhalter "?" mit dem Wert 123 und führen Sie dann die Abfrage aus und geben Sie ein Ergebnis für SELECT * FROM FOO WHERE ID = 123 zurück
Peter Wone
1
Hoppla, diese Syntax ist nur für Verbindungsserver verfügbar.
Peter Wone
1
Absolut einer der Hauptgründe für die Verwendung von sp_executesql, wenn die Abfrage dynamisch erstellt wird, um eine SQL-Injektion zu verhindern.
Steven Rogers
5

In dem Artikel " Using sp_executesql" von Microsoft wird die Verwendung sp_executesqlanstelle der executeAnweisung empfohlen .

Da diese gespeicherte Prozedur die Parametersubstitution unterstützt , ist sp_executesql vielseitiger als EXECUTE. und da sp_executesql Ausführungspläne generiert, die mit größerer Wahrscheinlichkeit von SQL Server wiederverwendet werden, ist sp_executesql effizienter als EXECUTE.

Also das Mitnehmen: Verwenden Sie keine executeAnweisung . Verwenden Sie sp_executesql.

Gan
quelle
7
Ihr Essen zum Mitnehmen steht nicht immer. Es gibt Fälle, in denen es mit sp_executesql keinen Effizienzbonus gibt, Sie Ihren Code jedoch vor einem SQL-Injection-Angriff schützen können. Manchmal kann man sp_executesql einfach nicht so verwenden, wie man exec verwenden kann, also ... sagte jemand - es gibt keine Silberkugel. Genau.
OzrenTkalcecKrznaric
Ja, Microsoft sollte es setzen als „eher wahrscheinlich , effizient zu sein“. Und seit einigen Jahren in der Branche, habe ich Fälle gesehen, in denen sp_executesqlnicht ersetzt werden kann execute. Vielleicht sollte ich den Punkt, den ich zu betonen versuche, wie folgt formulieren: Verwenden Sie sp_executesqlstatt execute wann immer möglich .
Gan
2

Ich würde heutzutage immer sp_executesql verwenden, alles was es wirklich ist, ist ein Wrapper für EXEC, der Parameter und Variablen behandelt.

Vergessen Sie jedoch nicht OPTION RECOMPILE, wenn Sie Abfragen in sehr großen Datenbanken optimieren, insbesondere wenn Sie Daten über mehr als eine Datenbank verteilt haben und eine Einschränkung verwenden, um Index-Scans einzuschränken.

Sofern Sie OPTION RECOMPILE nicht verwenden, versucht SQL Server, einen Ausführungsplan "Einheitsgröße" für Ihre Abfrage zu erstellen, und führt bei jeder Ausführung einen vollständigen Index-Scan durch.

Dies ist viel weniger effizient als eine Suche und bedeutet, dass möglicherweise ganze Indizes gescannt werden, die auf Bereiche beschränkt sind, die Sie nicht einmal abfragen: @

Ten98
quelle
-2
  1. Deklarieren Sie die Variable
  2. Stellen Sie es mit Ihrem Befehl ein und fügen Sie dynamische Teile hinzu, z. B. Parameterwerte von sp verwenden (hier sind @IsMonday und @IsTuesday sp-Parameter).
  3. Führen Sie den Befehl aus

    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
quelle
15
Dies ist offen für SQL-Injection, wenn Sie zB "a '; DROP DATABASE DATABASE_NAME; GO;';" in der @ IsMonday-Variablen
Erik A. Brandstadmoen
Ist es anfällig für SQL-Injektionen, wenn @IsMonday int ist?
Vikas Rana
@VikasRana @IsMonday kann nicht intin dynamischem SQL sein. Beachten Sie, dass @sql als varcharodernvarchar
Weihui Guo