Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Was kann ich tun, um die Leistung meiner reinen benutzerdefinierten Funktion in SQL Server zu verbessern?

Mein erster Gedanke hier ist:Was ist das Leistungsproblem? Sicher, Sie haben eine Schleife (einmal pro Zeile, um wo anzuwenden) innerhalb einer Schleife, die eine Abfrage ausführt. Aber bekommen Sie schlechte Ausführungspläne? Sind Ihre Ergebnismengen riesig? Aber wenden wir uns dem Generikum zu. Wie löst man dieses Problem einmal? SQL führt keine Memoisierung durch (wie der illustre @Martin_Smith betont). Also, was soll ein Junge tun?

Option 1 – Neues Design

Erstellen Sie ein völlig neues Design. In diesem speziellen Fall weist @Aaron_Bertrand darauf hin, dass eine Kalendertabelle Ihren Anforderungen entsprechen kann. Ganz recht. Dies hilft Ihnen nicht wirklich in Situationen, die keine Kalender sind, aber wie es oft in SQL der Fall ist, müssen Sie etwas anders denken.

Option 2 – Rufen Sie die UDF Less auf

Schränken Sie die Menge der Elemente ein, die diese Funktion aufrufen. Das erinnert mich sehr daran, wie man erfolgreich Paging/Zeilenzählung . Generieren Sie eine kleine Ergebnismenge mit den erforderlichen eindeutigen Werten and then Rufen Sie Ihre UDF auf, damit sie nur wenige Male aufgerufen wird. Dies kann eine Option sein oder auch nicht, kann aber in vielen Szenarien funktionieren.

Option 3 – Dynamische UDF

Ich werde wahrscheinlich für diesen Vorschlag aus dem Raum ausgebuht, aber hier geht's. Was diese UDF langsam macht, ist die select-Anweisung innerhalb der Schleife. Wenn sich Ihr Feiertagstisch wirklich selten ändert, können Sie einen Auslöser für den Tisch setzen. Der Trigger würde UDF ausschreiben und aktualisieren. Die neue UDF könnte alle Feiertagsentscheidungen brutal erzwingen. Wäre es ein bisschen wie Kannibalismus, wenn SQL SQL schreibt? Sicher. Aber es würde die Unterabfrage beseitigen und die UDF beschleunigen. Lassen Sie das Zwischenrufen beginnen.

Option 4 – Auswendig lernen!

Während SQL nicht direkt memoize kann, haben wir SQL CLR. Konvertieren Sie die UDF in eine SQL CLR-UDF. In CLR können Sie statische Variablen verwenden. Sie können die Holidays-Tabelle problemlos in regelmäßigen Abständen abrufen und in einer Hash-Tabelle speichern. Dann schreiben Sie einfach Ihre Schleife in der CLR neu. Sie könnten sogar noch weiter gehen und die gesamte Antwort auswendig lernen, wenn dies der angemessenen Logik entspricht.

Aktualisierung:

Option 1 - Ich habe wirklich versucht, mich hier auf das Allgemeine zu konzentrieren, nicht auf die Beispielfunktion, die Sie oben verwendet haben. Das derzeitige Design Ihrer UDF ermöglicht jedoch mehrere Aufrufe der Feiertagstabelle, wenn Sie zufällig ein paar hintereinander treffen. Durch die Verwendung einer Art kalenderartiger Tabelle, die eine Liste mit „schlechten Tagen“ und dem entsprechenden „nächsten Werktag“ enthält, können Sie das Potenzial für mehrere Treffer und Abfragen beseitigen.

Option 3 - Während die Domäne im Voraus unbekannt ist, können Sie Ihre Feiertagstabelle sehr gut ändern. Für einen bestimmten Feiertag würde es den nächsten entsprechenden Arbeitstag enthalten. Aus diesen Daten könnten Sie eine UDF mit einer langen Groß-/Kleinschreibung (wenn '5/5/2012', dann '5/14/2012' oder so ähnlich) unten ausspucken. Diese Strategie funktioniert möglicherweise nicht für alle Arten von Problemen, könnte aber für einige Arten von Problemen gut funktionieren.

Option 4 – Jede Technologie hat Auswirkungen. CLR muss bereitgestellt werden, die SQL Server-Konfiguration muss geändert werden, und SQL CLR ist auf das 3.5-Framework beschränkt. Persönlich fand ich diese Anpassungen einfach genug, aber Ihre Situation kann anders sein (z. B. ein widerspenstiger DBA oder Einschränkungen bei Änderungen an Produktionsservern).

Die Verwendung statischer Variablen erfordert die Assemblys VOLLES VERTRAUEN gewährt . Sie müssen sicherstellen, dass Sie Ihre Verriegelung richtig einstellen.

Es gibt einige Beweise das sehr hoch Transaktionsebenen CLR ist nicht so leistungsfähig wie direktes SQL. In Ihrem Szenario ist diese Beobachtung jedoch möglicherweise nicht anwendbar, da es keine direkte SQL-Korrelation für das gibt, was Sie zu tun versuchen (memoize).