Funktionen vs gespeicherte Prozeduren

88

Angenommen, ich muss einen Teil des T-SQL-Codes implementieren, der als Ergebnis eine Tabelle zurückgeben muss. Ich kann eine Tabellenwertfunktion oder eine gespeicherte Prozedur implementieren, die eine Reihe von Zeilen zurückgibt. Was soll ich verwenden?

Kurz gesagt, was ich wissen möchte, ist:

Was sind die Hauptunterschiede zwischen Funktionen und gespeicherten Prozeduren? Welche Überlegungen muss ich bei der Verwendung des einen oder anderen berücksichtigen?

Auron
quelle
1
Dies scheint die perfekte Antwort zu sein: stackoverflow.com/a/1179778/365188
Ozair Kafray

Antworten:

51

Wenn Sie das Ergebnis dieses Codeteils wahrscheinlich mit anderen Tabellen kombinieren möchten, können Sie die Ergebnisse natürlich mit einer Tabellenwertfunktion in einer einzigen SELECT-Anweisung zusammenstellen.

Im Allgemeinen gibt es eine Hierarchie (View <TV Function <Stored Proc). Sie können in jedem einzelnen mehr tun, aber die Fähigkeit, die Ausgaben zusammenzustellen und das Optimierungsprogramm wirklich einzubeziehen, nimmt mit zunehmender Funktionalität ab.

Verwenden Sie also dasjenige, mit dem Sie Ihr gewünschtes Ergebnis minimal ausdrücken können.

Damien_The_Unbeliever
quelle
50

Funktionen müssen deterministisch sein und können nicht zum Vornehmen von Änderungen an der Datenbank verwendet werden, wohingegen gespeicherte Prozeduren das Einfügen und Aktualisieren usw. ermöglichen.

Sie sollten die Verwendung von Funktionen einschränken, da diese ein großes Skalierbarkeitsproblem für große, komplexe Abfragen darstellen. Sie werden zu einer Art "Black Box" für den Abfrageoptimierer, und Sie werden enorme Leistungsunterschiede zwischen der Verwendung von Funktionen und dem einfachen Einfügen des Codes in eine Abfrage feststellen.

Aber sie sind definitiv nützlich für Tabellenrenditen in ganz bestimmten Fällen.

Wenn Sie eine durch Kommas getrennte Liste analysieren müssen, um die Übergabe eines Arrays an eine Prozedur zu simulieren, kann eine Funktion die Liste in eine Tabelle für Sie verwandeln. Dies ist bei SQL Server 2005 üblich, da wir noch keine Tabellen an gespeicherte Prozeduren übergeben können (dies ist bei 2008 möglich).

Eric Z Bart
quelle
1
Sie können jedoch XML an eine gespeicherte Prozedur senden: stackoverflow.com/questions/144550/…
cllpse
2
Falsch, die meisten SQL Server-Funktionen sind nicht deterministisch, z. B. getdate in MS-SQL Server. Nur ODBC-Funktionen sind kanonische Funktionen (= viel schneller + indizierbar) ... Aber Sie sind sehr korrekt, man sollte die Verwendung von Funktionen in Abfragen aus Leistungsgründen so weit wie möglich einschränken.
Stefan Steiger
45

Aus den Dokumenten :

Wenn eine gespeicherte Prozedur die folgenden Kriterien erfüllt, ist sie ein guter Kandidat für das Umschreiben als Tabellenwertfunktion:

  • Die Logik kann in einer einzelnen SELECT-Anweisung ausgedrückt werden, ist jedoch nur aufgrund der Notwendigkeit von Parametern eine gespeicherte Prozedur und keine Ansicht.

  • Die gespeicherte Prozedur führt keine Aktualisierungsvorgänge aus, außer für Tabellenvariablen.

  • Es sind keine dynamischen EXECUTE-Anweisungen erforderlich.

  • Die gespeicherte Prozedur gibt eine Ergebnismenge zurück.

  • Der Hauptzweck der gespeicherten Prozedur besteht darin, Zwischenergebnisse zu erstellen, die in eine temporäre Tabelle geladen werden sollen, die dann in einer SELECT-Anweisung abgefragt wird.

Christoffer Lette
quelle
12

Ich werde einige interessante Unterschiede zwischen gespeicherten Prozeduren und Funktionen schreiben.

  • Wir können Funktionen in ausgewählten Abfragen verwenden, aber wir können keine gespeicherten Prozeduren in ausgewählten Abfragen verwenden.
  • Wir können keine nicht deterministischen Funktionen in Funktionen verwenden, aber wir können nicht deterministische Funktionen in gespeicherten Prozeduren verwenden. Nun stellt sich die Frage, was nicht deterministische Funktion ist. Ans ist: -

    Eine nicht deterministische Funktion ist die Funktion, die unterschiedliche Ausgaben für dieselben Eingabewerte zu unterschiedlichen Zeiten zurückgibt, wie z. B. getdate (). Es wird immer ein anderer Wert zurückgegeben, wenn es ausgeführt wird.

    Ausnahme:-

    Frühere Versionen von SQL Server vor SQL 2000 erlauben nicht die Verwendung der Funktion getdate () in benutzerdefinierten Funktionen, aber ab Version 2005 können wir die Funktion getdate () in einer benutzerdefinierten Funktion verwenden.

    Newid () ist ein weiteres Beispiel für eine nicht deterministische Funktion, kann jedoch nicht in benutzerdefinierten Funktionen verwendet werden, wir können sie jedoch in gespeicherten Prozeduren verwenden.

  • Wir können DML-Anweisungen (Einfügen, Aktualisieren, Löschen) innerhalb einer gespeicherten Prozedur verwenden, aber wir können DML-Anweisungen nicht in Funktionen für physische Tabellen oder permanente Tabellen verwenden. Wenn wir DML-Operationen in Funktionen ausführen möchten, können wir dies über Tabellenvariablen tun, die nicht für permanente Tabellen gelten.

  • Wir können die Fehlerbehandlung nicht innerhalb der Funktion verwenden, aber wir können die Fehlerbehandlung in gespeicherten Prozeduren durchführen.

Neeraj Kumar Yadav
quelle
Wie kommt es, dass DML-Operationen in MySQL-Funktionen unterstützt werden?
Joey Pinto
@ JoeyPinto. Weil myNONsql keine SQL-Beschwerde ist. Sicher, es hat Extras, aber nicht die Grundlagen.
PerformanceDBA
8
  1. Die Prozedur kann null oder n Werte zurückgeben, während die Funktion einen obligatorischen Wert zurückgeben kann.

  2. Prozeduren können Eingabe- / Ausgabeparameter haben, während Funktionen nur Eingabeparameter haben können.

  3. Die Prozedur erlaubt sowohl die Select- als auch die DML-Anweisung, während die Funktion nur die Select-Anweisung darin zulässt.

  4. Funktionen können von der Prozedur aufgerufen werden, während Prozeduren nicht von der Funktion aufgerufen werden können.

  5. Die Ausnahme kann vom Try-Catch-Block in einer Prozedur behandelt werden, während der Try-Catch-Block in einer Funktion nicht verwendet werden kann.

  6. Wir können das Transaktionsmanagement im Verfahren durchführen, während wir die Funktion nicht übernehmen können.

  7. Prozeduren können nicht in einer select-Anweisung verwendet werden, während die Funktion in eine select-Anweisung eingebettet werden kann.

  8. UDF (User Defined Function) kann in den SQL-Anweisungen an einer beliebigen Stelle im Abschnitt WHERE/ HAVING/ verwendet werden, SELECTwährend gespeicherte Prozeduren dies nicht können.

  9. UDFs, die Tabellen zurückgeben, können als ein anderes Rowset behandelt werden. Dies kann in JOINs mit anderen Tabellen verwendet werden.

  10. Inline-UDFs können jedoch als Ansichten verwendet werden, die Parameter annehmen und in JOINs- und anderen Rowset-Operationen verwendet werden können.

nathan1138
quelle
6

Wenn Sie eine Funktion haben, können Sie diese beispielsweise als Teil Ihrer SQL-Anweisung verwenden

SELECT function_name(field1) FROM table

Bei den gespeicherten Prozeduren funktioniert dies nicht.

Ilya Kochetov
quelle
1
Ich denke, er hat über Funktionen gesprochen, die Tabellenwerte zurückgeben.
wcm
1
Nun, ich spreche im Allgemeinen. Aber für meinen speziellen Fall bin ich jetzt zwischen einer gespeicherten Prozedur oder einer Tabellenwertfunktion.
Auron
5

Ich habe einige Tests mit einer langen Logik ausgeführt, wobei das gleiche Codebit (eine lange SELECT-Anweisung) sowohl in einer Tabellenwertfunktion als auch in einer gespeicherten Prozedur und einer geraden EXEC / SELECT-Funktion ausgeführt wurde und jeweils identisch ausgeführt wurde.

Meiner Meinung nach verwenden Sie immer eine Tabellenwertfunktion anstelle einer gespeicherten Prozedur, um eine Ergebnismenge zurückzugeben, da dies die Logik in Abfragen, die anschließend mit ihnen verknüpft werden, viel einfacher und lesbarer macht und es Ihnen ermöglicht, dieselbe Logik wiederzuverwenden. Um zu viele Leistungseinbußen zu vermeiden, verwende ich häufig "optionale" Parameter (dh Sie können NULL an sie übergeben), damit die Funktion die Ergebnismenge schneller zurückgeben kann, z.

CREATE FUNCTION dbo.getSitePermissions(@RegionID int, @optPersonID int, optSiteID int)
AS
RETURN 
    SELECT DISTINCT SiteID, PersonID
    FROM dbo.SiteViewPermissions
    WHERE (@optPersonID IS NULL OR @optPersonID = PersonID)
    AND (@optSiteID IS NULL OR @optSiteID = SiteID)
    AND @RegionID = RegionID

Auf diese Weise können Sie diese Funktion für viele verschiedene Situationen verwenden und keinen großen Leistungseinbruch erleiden. Ich glaube, das ist effizienter als das anschließende Filtern:

SELECT * FROM dbo.getSitePermissions(@RegionID) WHERE SiteID = 1

Ich habe diese Technik in mehreren Funktionen verwendet, manchmal mit einer langen Liste von "optionalen" Parametern dieses Typs.

Paul Grimshaw
quelle
4

Ich persönlich verwende Tabellenwertfunktionen, wenn ich nur eine einzelne Tabelle ohne Auswirkungen zurückgebe. Grundsätzlich behandle ich sie wie parametrisierte Ansichten.

Wenn mehrere Datensätze zurückgegeben werden müssen oder wenn Werte in Tabellen aktualisiert werden, verwende ich eine gespeicherte Prozedur.

Meine 2 Cent

wcm
quelle
4

Wie oben erwähnt, sind Funktionen besser lesbar / zusammensetzbar / selbstdokumentierend, aber im Allgemeinen weniger performant und können ernsthaft weniger performant sein, wenn Sie sie in Verknüpfungen wie z

SELECT *
FROM dbo.tvfVeryLargeResultset1(@myVar1) tvf1
INNER JOIN dbo.tvfVeryLargeResultset1(@myVar2) tvf2
    ON (tvf1.JoinId = tvf2.JoinId)

Oft muss man nur die Redundanz des Codes akzeptieren, die ein Fernsehgerät beseitigen könnte (zu inakzeptablen Leistungskosten).

Ein weiterer Punkt, den ich noch nicht erwähnt habe, ist, dass Sie keine temporären Tabellen zur Änderung des Datenbankstatus in einem TVF mit mehreren Anweisungen verwenden können. Der funktional am besten zu einer temporären Tabelle äquivalente Mechanismus ist die Änderung der Speichertabellenvariablen ohne Status. Bei großen Datenmengen ist eine temporäre Tabelle wahrscheinlich leistungsfähiger als eine Tabellenvariable. (Andere Alternativen sind dynamische Tabellen und allgemeine Ausdrücke mit Tabellenwerten, aber bei einer gewissen Komplexität sind diese keine gute Option mehr, IMO.)

6eorge Jetson
quelle
1

Ich würde beides perfromance testen. Es ist wahrscheinlich, dass der sp-Ansatz oder eine abgeleitete Tabelle erheblich schneller als eine Funktion ist, und wenn ja, sollte dieser Ansatz verwendet werden. Im Allgemeinen vermeide ich Funktionen, da sie Leistungsfresser sein können.

HLGEM
quelle
1

Es hängt davon ab :) Wenn Sie das Ergebnis mit Tabellenwert in einer anderen Prozedur verwenden möchten, sollten Sie eine TableValued-Funktion verwenden. Wenn die Ergebnisse für einen Kunden sind, ist der gespeicherte Prozess normalerweise der bessere Weg.

edosoft
quelle
-1

Gespeicherte Prozeduren sind vorkompilierte Abfragen, die schneller ausgeführt und vor den SQL-Injektionen geschützt werden. Sie können 0 oder N Werte zurückgeben. Wir können DML-Operationen innerhalb der gespeicherten Prozeduren ausführen. Wir können Funktionen innerhalb der Prozeduren und Funktionen in der Auswahlabfrage verwenden. Funktionen werden verwendet, um Werte zurückzugeben, und DML-Operationen sind in Funktionen nicht möglich. Es gibt zwei Arten von Funktionen, die skalar und tabellarisch sind. Die Skalarfunktion gibt eine Einzelwertfunktion mit Tabellenwerten zurück, mit der Tabellenzeilen zurückgegeben werden.

Harish Madaan
quelle
Dies ist eine sehr alte Frage mit einer großen Anzahl von Antworten, von denen viele (einschließlich der akzeptierten Antwort) hoch bewertet sind. Bevor Sie einem solchen Thread eine weitere Antwort hinzufügen, sollten Sie sich fragen: "Was fehlt all diesen vorhandenen Antworten, sodass ich eine weitere schreiben muss?"
APC