Parameter-Sniffing: Warum wird dies zu einem Problem?

7

Heute hatte ich ein Problem mit einem Zeitlimit für gespeicherte Prozeduren (das länger als 30 Sekunden dauerte), als es von einer ASP.NET-Webseite ausgeführt wurde, das jedoch schnell ausgeführt wurde, wenn es von SSMS ausgeführt wurde (dauerte 5 Sekunden).

Nachdem ich den Verdacht hatte, dass Parameter als Schuldiger geschnüffelt wurden, maskierte ich die Eingabeparameter und die Abfrage wurde schneller ausgeführt.

Meine Frage ist: Warum ist das passiert?

Dieses System ist seit mehr als 5 Jahren in Produktion und dies ist das erste Mal, dass wir so etwas auf unseren gespeicherten Prozeduren sehen. Ist das "Datenbankverschleiß"?

Wir haben das Problem gelöst, es ist also keine große Sache, aber ich bin nur neugierig, warum dies geschah.

Zwiebelritter
quelle
Siehe diese auch auf SO bitte: stackoverflow.com/…
gbn
Ich habe das schon ziemlich oft gesehen. Am Ende der meisten meiner DROP/ CREATE PROC.sql-Dateien füge ich normalerweise ein EXECfor the sproc mit realistischen Parametern ein. Jedes Mal, wenn der Sproc neu erstellt wird, wird er einmal mit guten Parametern ausgeführt und (sollte) einen guten Ausführungsplan erhalten.
Jon of All Trades

Antworten:

8

Wenn SQL Server eine Abfrage sieht, die kompiliert werden muss, verwendet es im Grunde genommen die erstmalig aufgerufenen Parameter, um den Ausführungsplan zu generieren. Dies kann eine gute Sache sein oder auch nicht, aber es ist das, was passiert.

Angenommen, Sie haben eine Obsttabelle (100 Zeilen). Es gibt 98 Reihen, die Apfel sind, und nur 2 Reihen, die die Fruchtorange enthalten. Wenn Sie diese Tabelle nach Apple abfragen, wird der Plan höchstwahrscheinlich mit einem Scan kompiliert. Dies ist eine gute Sache, da es für diese Apple-Abfrage optimiert ist. Wenn Sie jedoch nach Orange fragen möchten, ist dieser Scan ineffizient. Es wird jedoch der gespeicherte Plan verwendet.

Tatsache ist, dass es passiert. Es passiert ständig. Es ist normalerweise kein offenes Problem, aber in einigen Fällen kann es ein ziemlich großes Problem sein. Eine Lösung für ein anhaltend schlechtes Problem beim Sniffing von Parametern besteht darin, dass Sie den OPTIMIZE FORAbfragehinweis verwenden können, um SQL Server zu zwingen, bestimmte Parameterwerte beim Generieren des Ausführungsplans bei der ersten Kompilierung zu verwenden.

Thomas Stringer
quelle
3
+1 Oder verwenden Sie OPTIMIZE FOR UNKNOWNoder OPTION RECOMPILEwenn die Planform stark variiert und es keinen einzigen Wert gibt, für den Sie wissentlich optimieren können.
Aaron Bertrand
@ AaronBertrand Gute Punkte auf denen. Ich persönlich musste es nie verwenden OPTION RECOMPILE, da ich mich lieber mit einem nicht optimalen zwischengespeicherten Plan befassen würde, als für jeden Anruf neu zu kompilieren.
Thomas Stringer
In einigen Fällen OPTION RECOMPILEist dies besser - der Kompilierungsaufwand kann im Vergleich zu einem wirklich schlechten Plan gering sein.
Aaron Bertrand
@ AaronBertrand Ich glaube es. Musstest du das in deiner Vergangenheit ein bisschen benutzen?
Thomas Stringer
Ja, sehr haariges dynamisches SQL für die Suche mit vielen optionalen Parametern. OPTION RECOMPILEund später optimize for ad hoc workloadswirklich geholfen.
Aaron Bertrand
6

... aber schnell ausgeführt, wenn es von SSMS ausgeführt wird (dauerte 5 Sekunden)

Eher ärgerlich ist, dass die SSMS-Standardeinstellung für SET ARITHABORT ONdie meisten Client-Bibliotheken (ADO .Net, ODBC, OLE DB) angegeben ist SET ARITHABORT OFF. Wahrscheinlich hatten Sie einen Plan "schlecht", aber als Sie versuchten, über SSMS zu replizieren, führte der Unterschied in ARITHABORT dazu, dass ein anderer Plan verwendet wurde, der "gut" war.

Langsam in der Anwendung, schnell in SSMS? ist eine gute Referenz dafür.

Warum ist das passiert?

Höchstwahrscheinlich wurde eine Neukompilierung ausgelöst und leider wurde ein nicht typischer Satz von Eingaben für die Kompilierung verwendet.

Mark Storey-Smith
quelle