Gibt es eine Möglichkeit, zu verhindern, dass skalare UDFs in berechneten Spalten die Parallelität verhindern?

29

Es wurde viel über die Gefahren von Scalar-UDFs in SQL Server geschrieben. Eine gelegentliche Suche liefert unzählige Ergebnisse.

Es gibt jedoch einige Stellen, an denen eine skalare UDF die einzige Option ist.

Beispiel: Wenn Sie mit XML arbeiten: XQuery kann nicht als berechnete Spaltendefinition verwendet werden. Eine von Microsoft dokumentierte Option besteht darin, eine Scalar-UDF zu verwenden, um Ihre XQuery in eine Scalar-UDF zu kapseln, und sie dann in einer berechneten Spalte zu verwenden.

Dies hat verschiedene Auswirkungen und einige Problemumgehungen.

  • Führt Zeile für Zeile aus, wenn die Tabelle abgefragt wird
  • Erzwingt die serielle Ausführung aller Abfragen für die Tabelle

Sie können die zeilenweise Ausführung umgehen, indem Sie die Funktion schematisieren und die berechnete Spalte entweder beibehalten oder indizieren. Keine dieser Methoden kann die erzwungene Serialisierung von Abfragen verhindern, die auf die Tabelle treffen, selbst wenn auf die skalare UDF nicht verwiesen wird.

Gibt es dafür einen bekannten Weg?

Erik Darling
quelle

Antworten:

31

Ja, wenn Sie:

  • SQL Server 2014 oder höher ausführen; und
  • sind in der Lage, die Abfrage mit aktivem Ablaufverfolgungsflag 176 auszuführen ; und
  • Die berechnete Spalte ist PERSISTED

Insbesondere sind mindestens die folgenden Versionen erforderlich :

  • Kumulatives Update 2 für SQL Server 2016 SP1
  • Kumulatives Update 4 für SQL Server 2016 RTM
  • Kumulatives Update 6 für SQL Server 2014 SP2

ABER um einen in diesen Fixes eingeführten Bug (Ref. Für 2014 und für 2016 und 2017 ) zu vermeiden , gilt Folgendes:

Das Ablaufverfolgungsflag ist als Startoption wirksam –T, sowohl im globalen als auch im Sitzungsbereich unter Verwendung von DBCC TRACEONund pro Abfrage mit OPTION (QUERYTRACEON)oder mit einem Planungsleitfaden.

Das Ablaufverfolgungsflag 176 verhindert eine anhaltende Erweiterung der berechneten Spalten.

Das anfängliche Laden von Metadaten, das beim Kompilieren einer Abfrage ausgeführt wird, enthält alle Spalten, nicht nur die direkt referenzierten. Dies macht alle berechneten Spaltendefinitionen für den Abgleich verfügbar, was im Allgemeinen eine gute Sache ist.

Als unglücklicher Nebeneffekt deaktiviert das Vorhandensein einer der geladenen (berechneten) Spalten eine skalare benutzerdefinierte Funktion die Parallelität für die gesamte Abfrage, auch wenn die berechnete Spalte nicht tatsächlich verwendet wird .

Das Ablaufverfolgungsflag 176 hilft dabei, wenn die Spalte beibehalten wird, indem die Definition nicht geladen wird (da die Erweiterung übersprungen wird). Auf diese Weise ist in der kompilierten Abfragestruktur keine skalare benutzerdefinierte Funktion vorhanden, sodass die Parallelität nicht deaktiviert wird.

Der Hauptnachteil des Ablaufverfolgungsflags 176 (abgesehen davon, dass es nur geringfügig dokumentiert ist) ist, dass es auch verhindert, dass Abfrageausdrücke mit persistierten berechneten Spalten übereinstimmen: Wenn die Abfrage einen Ausdruck enthält, der mit einer persistierten berechneten Spalte übereinstimmt, verhindert das Ablaufverfolgungsflag 176, dass der Ausdruck durch ersetzt wird ein Verweis auf die berechnete Spalte.

Weitere Informationen finden Sie in meinem SQLPerformance.com-Artikel Ordnungsgemäß beibehaltene berechnete Spalten .

Da in der Frage XML als Alternative zum Heraufstufen von Werten mithilfe einer berechneten Spalten- und Skalarfunktion erwähnt wird, können Sie sich auch die Verwendung eines selektiven XML-Index ansehen, wie Sie in Selektive XML-Indizes beschrieben haben: Gar nicht schlecht .

Paul White sagt GoFundMonica
quelle
10

Zusätzlich zu @ Pauls exzellentem Ja # 1 gibt es tatsächlich ein Ja # 2, das:

  • funktioniert bis zu SQL Server 2005,
  • setzt kein Trace-Flag voraus,
  • erfordert nicht , dass die berechnete Spalte PERSISTEDund ist
  • (Da das Ablaufverfolgungsflag 176 nicht erforderlich ist) verhindert nicht, dass der Abfrageausdruck mit persistierten berechneten Spalten übereinstimmt

Die einzigen Nachteile (soweit ich das beurteilen kann) sind:

  • funktioniert nicht in der Azure SQL-Datenbank (zumindest noch nicht, obwohl dies sowohl in Amazon RDS SQL Server als auch in SQL Server unter Linux funktioniert), und
  • liegt etwas außerhalb der Komfortzone vieler DBAs

Und diese Option lautet: SQLCLR

Korrekt. Ein cooler Aspekt von SQLCLR-Scalar-UDFs ist, dass sie keine Parallelität verbieten , wenn sie keinen Datenzugriff durchführen (weder Benutzer noch System). Und das ist nicht nur Theorie oder Marketing. Obwohl ich (im Moment) keine Zeit habe, die ausführliche Beschreibung vorzunehmen, habe ich dies getestet und bewiesen.

Ich habe das anfängliche Setup aus dem folgenden Blog-Beitrag verwendet (hoffentlich betrachtet das OP dies nicht als unzuverlässige Quelle 🙃):

Bad Idea Jeans: Mehrere Indexhinweise

Und führte die folgenden Tests durch:

  1. Lief die anfängliche Abfrage wie folgt ab: ism Parallelität (wie erwartet)
  2. Es wurde eine nicht persistente berechnete Spalte ([c2] * [c3])hinzugefügt, die wie erwartet als ─⇾ Parallelität definiert ist.
  3. Entfernte diese berechnete Spalte und fügte eine nicht persistente berechnete Spalte hinzu, die auf eine T-SQL-Skalar-UDF (erstellt mit SCHEMABINDING) RETURN (@First * @Second);verwies, die wie erwartet als ─⇾ NO Parallelism definiert wurde.
  4. Die berechnete T-SQL-UDF-Spalte wurde entfernt und eine nicht persistierte berechnete Spalte hinzugefügt, die auf eine skalare SQLCLR-UDF (mit beiden IsDeterministic = trueund ausprobiert = false) return SqlInt32.Multiply(First, Second);verweist, die als as Parallelität (woo hoo !!) definiert ist.

Obwohl SQLCLR nicht für alle geeignet ist, hat es sicherlich seine Vorteile für diejenigen Menschen / Situationen / Umgebungen, die gut zusammenpassen. Und da es sich um diese spezielle Frage handelt - das angegebene Beispiel für die Verwendung von XQuery -, würde dies sicherlich funktionieren (und je nachdem, was konkret getan wird, könnte es sogar etwas schneller sein 😎).

Solomon Rutzky
quelle