Kann sp_executesql standardmäßig konfiguriert / verwendet werden?

10

Ich betrachte eine Anwendung, die hochdynamische SQL-Abfragen für SQL Server verwendet. Wenn ich mir die Abfragen ansehe, die auf sehr seltsame und komplizierte Weise aufgebaut sind, aber das ist eine andere Geschichte, erzähle ich sie, um einen guten Grund dafür zu nennen, dass ich nicht in der Lage (zu dumm) bin, Dinge selbst herauszufinden ... Ich kann nicht sehen Jeder Code, mit dem die Abfragen umbrochen werden sp_executesql.

Aber wenn ich nachverfolge, sehe ich viele Anfragen, die mit eingepackt eingehen sp_executesql. Die gesamte Anwendungslösung enthält überhaupt nicht den Befehl sp_executesql.

Also habe ich mich gefragt, ob es eine Konfiguration gibt, die ich noch nicht kenne und die die Software zwingt, Abfragen standardmäßig mit sp_executesql zu verpacken.

Was könnte dieses Verhalten verursachen?

Magier
quelle

Antworten:

11

Der Grund, warum die SQL-Anweisungen umbrochen werden, sp_executesqlist die Einstellung der SqlCommand.CommandtypeEigenschaft und die Übergabe von Parametern an den Befehl.

SqlCommand cmd = new SqlCommand("proc1", con);
cmd.CommandType = CommandType.StoredProcedure;                
cmd.Parameters.AddWithValue("@param1", 1);
con.Open();
cmd.ExecuteNonQuery();
con.Close();

Der obige Code endet mit diesem T-SQL:

exec proc1 @param1=1
SqlCommand cmd = new SqlCommand("proc1", con);
cmd.CommandType = CommandType.Text;                
cmd.Parameters.AddWithValue("@param1", 1);
con.Open();
cmd.ExecuteNonQuery();
con.Close();

Dieser Code endet mit der Ausführung des folgenden T-SQL:

exec sp_executesql N'proc1',N'@param1 int',@param1=1

Ergänzung 23.12.15: Bei Verwendung eines CommandType.TextBefehls sind die Ergebnisse ähnlich: Sobald dem Befehlsobjekt ein Parameter hinzugefügt wird, wird .NET die gesamte Abfrage in einen Befehl einschließensp_executesql und die Parameter an diesen übergeben.

Ergänzung: Nach einem tieferen Einblick in das sp_executesqlParameter-Sniffing und das Plan-Caching ist dieses Verhalten der .NET-Klassen absolut sinnvoll, um eine häufige Kompilierung von Abfragen und die Anzahl der Pläne zu vermeiden. Es wurde daher im Wesentlichen entwickelt, um eine bessere SQL Server-Leistung im Allgemeinen sicherzustellen, während es gleichzeitig zu einer schlechten Leistung einiger Abfragen (Parameter-Sniffing-Problem) führen kann, die mit anderen Parameterwerten als dem ursprünglich erstellten Abfrageplan verwendet werden.

Sehen:

Das obige Beispiel wurde mit .NET Framework 4.5 und SQL Server 2008 Developer Edition erstellt.

Magier
quelle
5

Wenn es sich um eine .NET-Anwendung handelt, ist es sehr wahrscheinlich, dass SqlCommand.ExecuteReader () aufgerufen wird. Laut der Hauptseite der SqlCommand- Klasse steht im Raster der Methodenbeschreibungen im Abschnitt "Bemerkungen" unter ExecuteReader Folgendes :

Führt Befehle aus, die Zeilen zurückgeben. Um die Leistung zu steigern, ruft ExecuteReader Befehle mit der gespeicherten Systemprozedur Transact-SQL sp_executesql auf. Daher hat ExecuteReader möglicherweise nicht den gewünschten Effekt, wenn Befehle zum Ausführen von Befehlen wie Transact-SQL SET-Anweisungen verwendet werden.

Ich habe jetzt keine Zeit, dies zu testen, um ihre Beschreibung zu bestätigen, aber es sollte einfach genug sein, eine einfache Konsolen-App zu erstellen, die einen sehr einfachen Aufruf ausführt, einen Abfragetext übergibt und einen Parameter enthält, der mit a geliefert wird SqlParameter. Ich vermute, dass ExecuteNonQueryund ExecuteScalarverwenden sp_executesqlSie auch, da sie auch die Übergabe von Parametern ermöglichen. Warum sollte es also einen anderen Pfad für die Ausführung dieser Parameter geben?

Solomon Rutzky
quelle