Ein paar Beispiele zu zeigen, nur für den Fall:
Inline-Tabelle bewertet
CREATE FUNCTION MyNS.GetUnshippedOrders()
RETURNS TABLE
AS
RETURN SELECT a.SaleId, a.CustomerID, b.Qty
FROM Sales.Sales a INNER JOIN Sales.SaleDetail b
ON a.SaleId = b.SaleId
INNER JOIN Production.Product c ON b.ProductID = c.ProductID
WHERE a.ShipDate IS NULL
GO
Multi Statement Table bewertet
CREATE FUNCTION MyNS.GetLastShipped(@CustomerID INT)
RETURNS @CustomerOrder TABLE
(SaleOrderID INT NOT NULL,
CustomerID INT NOT NULL,
OrderDate DATETIME NOT NULL,
OrderQty INT NOT NULL)
AS
BEGIN
DECLARE @MaxDate DATETIME
SELECT @MaxDate = MAX(OrderDate)
FROM Sales.SalesOrderHeader
WHERE CustomerID = @CustomerID
INSERT @CustomerOrder
SELECT a.SalesOrderID, a.CustomerID, a.OrderDate, b.OrderQty
FROM Sales.SalesOrderHeader a INNER JOIN Sales.SalesOrderHeader b
ON a.SalesOrderID = b.SalesOrderID
INNER JOIN Production.Product c ON b.ProductID = c.ProductID
WHERE a.OrderDate = @MaxDate
AND a.CustomerID = @CustomerID
RETURN
END
GO
Gibt es einen Vorteil bei der Verwendung eines Typs (Inline- oder Multi-Anweisung) gegenüber dem anderen? Gibt es bestimmte Szenarien, in denen eines besser ist als das andere, oder sind die Unterschiede rein syntaktisch? Mir ist klar, dass die beiden Beispielabfragen unterschiedliche Aufgaben haben, aber gibt es einen Grund, warum ich sie so schreiben würde?
Das Lesen über sie und die Vorteile / Unterschiede wurde nicht wirklich erklärt.
Antworten:
Bei der Untersuchung von Matts Kommentar habe ich meine ursprüngliche Aussage überarbeitet. Er hat Recht, es wird einen Leistungsunterschied zwischen einer Inline-Tabellenwertfunktion (ITVF) und einer Tabellenfunktion mit mehreren Anweisungen (MSTVF) geben, selbst wenn beide einfach eine SELECT-Anweisung ausführen. SQL Server behandelt eine ITVF ähnlich wie eine
VIEW
, dass ein Ausführungsplan unter Verwendung der neuesten Statistiken zu den betreffenden Tabellen berechnet wird. Ein MSTVF entspricht dem Einfügen des gesamten Inhalts Ihrer SELECT-Anweisung in eine Tabellenvariable und dem anschließenden Verbinden mit dieser. Daher kann der Compiler keine Tabellenstatistiken für die Tabellen in der MSTVF verwenden. Wenn alle Dinge gleich sind (was sie selten sind), wird der ITVF eine bessere Leistung erbringen als der MSTVF. In meinen Tests war der Leistungsunterschied in der Fertigstellungszeit vernachlässigbar, jedoch aus statistischer Sicht spürbar.In Ihrem Fall sind die beiden Funktionen funktional nicht äquivalent. Die MSTV-Funktion führt bei jedem Aufruf eine zusätzliche Abfrage durch und filtert vor allem die Kunden-ID. In einer großen Abfrage kann das Optimierungsprogramm andere Join-Typen nicht nutzen, da es die Funktion für jede übergebene Kunden-ID aufrufen muss. Wenn Sie Ihre MSTV-Funktion jedoch wie folgt neu geschrieben haben:
In einer Abfrage könnte der Optimierer diese Funktion einmal aufrufen und einen besseren Ausführungsplan erstellen, aber er wäre immer noch nicht besser als ein äquivalentes, nicht parametrisiertes ITVS oder ein
VIEW
.ITVFs sollten MSTVFs vorgezogen werden, wenn dies möglich ist, da die Datentypen, die Nullbarkeit und die Sortierung aus den Spalten in der Tabelle stammen, während Sie diese Eigenschaften in einer Tabellenfunktion mit mehreren Anweisungen deklarieren und vor allem bessere Ausführungspläne von der ITVF erhalten. Nach meiner Erfahrung habe ich nicht viele Umstände gefunden, unter denen ein ITVF eine bessere Option als ein VIEW war, aber der Kilometerstand kann variieren.
Danke an Matt.
Zusatz
Da ich dies kürzlich gesehen habe, ist hier eine hervorragende Analyse von Wayne Sheffield, die den Leistungsunterschied zwischen Inline Table Valued-Funktionen und Multi-Statement-Funktionen vergleicht.
Sein ursprünglicher Blogbeitrag.
Kopieren auf SQL Server Central
quelle
Intern behandelt SQL Server eine Inline-Tabellenwertfunktion ähnlich wie eine Ansicht und eine Tabellenfunktion mit mehreren Anweisungen ähnlich wie eine gespeicherte Prozedur.
Wenn eine Inline-Tabellenwertfunktion als Teil einer äußeren Abfrage verwendet wird, erweitert der Abfrageprozessor die UDF-Definition und generiert einen Ausführungsplan, der mithilfe der Indizes für diese Objekte auf die zugrunde liegenden Objekte zugreift.
Für eine Tabellenwertfunktion mit mehreren Anweisungen wird ein Ausführungsplan für die Funktion selbst erstellt und im Ausführungsplan-Cache gespeichert (sobald die Funktion zum ersten Mal ausgeführt wurde). Wenn Tabellenfunktionen mit mehreren Anweisungen als Teil größerer Abfragen verwendet werden, weiß der Optimierer nicht, was die Funktion zurückgibt, und trifft daher einige Standardannahmen. Tatsächlich wird davon ausgegangen, dass die Funktion eine einzelne Zeile zurückgibt und dass die Rückgabe von Auf die Funktion wird zugegriffen, indem ein Tabellenscan für eine Tabelle mit einer einzelnen Zeile verwendet wird.
Funktionen mit Tabellenwerten mit mehreren Anweisungen können eine schlechte Leistung erbringen, wenn sie eine große Anzahl von Zeilen zurückgeben und in äußeren Abfragen miteinander verknüpft werden. Die Leistungsprobleme sind hauptsächlich auf die Tatsache zurückzuführen, dass der Optimierer einen Plan erstellt, vorausgesetzt, dass eine einzelne Zeile zurückgegeben wird, was nicht unbedingt der am besten geeignete Plan ist.
Als allgemeine Faustregel haben wir festgestellt, dass Funktionen mit Inline-Tabellenwerten aufgrund dieser potenziellen Leistungsprobleme nach Möglichkeit gegenüber Funktionen mit mehreren Anweisungen bevorzugt werden sollten (wenn die UDF als Teil einer äußeren Abfrage verwendet wird).
quelle
Es gibt noch einen anderen Unterschied. Eine Inline-Tabellenwertfunktion kann wie eine Ansicht in eine Funktion eingefügt, aktualisiert und aus dieser gelöscht werden. Ähnliche Einschränkungen gelten - Funktionen können nicht mithilfe von Aggregaten aktualisiert werden, berechnete Spalten können nicht aktualisiert werden usw.
quelle
Ich denke, Ihre Beispiele beantworten die Frage sehr gut. Die erste Funktion kann als Einzelauswahl ausgeführt werden und ist ein guter Grund, den Inline-Stil zu verwenden. Die zweite könnte wahrscheinlich als einzelne Anweisung ausgeführt werden (unter Verwendung einer Unterabfrage, um das maximale Datum zu erhalten), aber einige Codierer finden es möglicherweise einfacher zu lesen oder natürlicher, sie in mehreren Anweisungen auszuführen, wie Sie es getan haben. Einige Funktionen können einfach nicht in einer Anweisung ausgeführt werden und erfordern daher die Version mit mehreren Anweisungen.
Ich schlage vor, wann immer möglich die einfachste (Inline) zu verwenden und bei Bedarf (offensichtlich) mehrere Anweisungen zu verwenden oder wenn persönliche Vorlieben / Lesbarkeit die zusätzliche Eingabe erforderlich machen.
quelle
Unter Vergleichen von Inline- und Multi-Statement-Funktionen mit Tabellenwerten finden Sie gute Beschreibungen und Leistungsbenchmarks
quelle
Ich habe dies nicht getestet, aber eine Funktion mit mehreren Anweisungen speichert die Ergebnismenge zwischen. Es kann Fälle geben, in denen zu viel los ist, als dass der Optimierer die Funktion einbinden könnte. Angenommen, Sie haben eine Funktion, die ein Ergebnis aus verschiedenen Datenbanken zurückgibt, je nachdem, was Sie als "Firmennummer" übergeben. Normalerweise können Sie eine Ansicht mit einer Union erstellen und dann nach Firmennummer filtern. Ich habe jedoch festgestellt, dass SQL Server manchmal die gesamte Union zurückzieht und nicht intelligent genug ist, um die eine Auswahl aufzurufen. Eine Tabellenfunktion kann logisch sein, um die Quelle auszuwählen.
quelle
Ein weiterer Fall für die Verwendung einer mehrzeiligen Funktion besteht darin, zu verhindern, dass SQL Server die where-Klausel herunterdrückt.
Zum Beispiel habe ich eine Tabelle mit Tabellennamen und einige Tabellennamen sind wie C05_2019 und C12_2018 formatiert, und alle auf diese Weise formatierten Tabellen haben dasselbe Schema. Ich wollte all diese Daten in einer Tabelle zusammenführen und 05 und 12 in einer CompNo-Spalte und 2018,2019 in einer Jahresspalte analysieren. Es gibt jedoch andere Tabellen wie ACA_StupidTable, die ich nicht mit CompNo und CompYr extrahieren kann und bei einem Versuch einen Konvertierungsfehler erhalten würde. Meine Abfrage bestand also aus zwei Teilen, einer inneren Abfrage, die nur Tabellen zurückgab, die wie 'C_______' formatiert waren. Dann führte die äußere Abfrage eine Konvertierung von Unterzeichenfolgen und Int durch. dh Cast (Teilstring (2, 2) als int) als CompNo. Alles sieht gut aus, außer dass der SQL Server beschlossen hat, meine Cast-Funktion zu setzen, bevor die Ergebnisse gefiltert wurden, und daher ein Konvertierungsfehler auftritt. Eine Tabellenfunktion mit mehreren Anweisungen kann dies verhindern.
quelle
Vielleicht auf sehr komprimierte Weise. ITVF (Inline-TVF): mehr, wenn Sie DB-Person sind, ist eine Art parametrisierte Ansicht, nehmen Sie eine einzelne SELECT st
MTVF (Multi-Statement TVF): Entwickler erstellt und lädt eine Tabellenvariable.
quelle
Wenn Sie eine Abfrage durchführen möchten, können Sie sich an Ihrer Inline Table Valued-Funktion wie folgt beteiligen:
es wird wenig Overhead verursachen und gut laufen.
Wenn Sie versuchen, die Multi-Statement-Tabelle Valued in einer ähnlichen Abfrage zu verwenden, treten Leistungsprobleme auf:
Da Sie die Funktion 1 Mal für jede zurückgegebene Zeile ausführen, wird die Ergebnismenge immer langsamer und langsamer ausgeführt.
quelle