ProgrammierungBackend-Entwickler

Wie implementiert man komplexe Geschäftsregeln und Berechnungen direkt in SQL mit benutzerdefinierten Funktionen (User Defined Functions, UDF)? Was sind die Unterschiede und Einschränkungen zwischen skalaren und tabellarischen UDFs, wann ist es sinnvoll, sie anzuwenden, und wann ist es besser, eine solche Logik in einer externen Anwendung zu implementieren?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

In SQL kann man Geschäftslogik durch benutzerdefinierte Funktionen (User Defined Functions, UDF) realisieren, wodurch ein Teil der Berechnungen und Geschäftsregeln in die Datenbank verlagert wird.

Skalare Funktionen geben einen einzelnen Wert zurück und werden in Ausdrücken aufgerufen — zum Beispiel, um einen Gesamtbetrag basierend auf Parametern zu berechnen:

CREATE FUNCTION dbo.GetDiscount(@price DECIMAL(10,2), @loyaltyLevel INT) RETURNS DECIMAL(10,2) AS BEGIN RETURN @price * CASE WHEN @loyaltyLevel = 1 THEN 0.95 WHEN @loyaltyLevel = 2 THEN 0.90 ELSE 1.0 END END; -- Beispielverwendung: SELECT Name, dbo.GetDiscount(Price, LoyaltyLevel) AS DiscountPrice FROM Products;

Tabellarische Funktionen geben eine Menge von Zeilen (Tabelle) zurück:

CREATE FUNCTION dbo.ActiveOrders(@userId INT) RETURNS TABLE AS RETURN ( SELECT * FROM Orders WHERE UserId = @userId AND Status = 'Active' ); -- Verwendung: SELECT * FROM dbo.ActiveOrders(123);

Unterschiede, Einschränkungen und Empfehlungen:

  • Skalare UDFs haben oft eine geringe Leistung bei großen Abfragen, da sie zeilenweise aufgerufen werden;
  • Tabellarische UDFs integrieren sich besser in Abfragepläne und können wie normale Tabellen verwendet werden;
  • Logik, die den Zugriff auf externe Ressourcen oder komplexe Geschäftsverarbeitung erfordert, sollte besser außerhalb von SQL ausgeführt werden.

Fangfrage.

Was ist der Unterschied zwischen einer INLINE tabellarischen Funktion und einer mehrstufigen (multi-statement) tabellarischen Funktion? Wie beeinflusst diese Wahl die Leistung?

Antwort und Beispiel:

  • Die INLINE-Funktion (single-statement, gibt sofort SELECT zurück) wird als Teil der Hauptabfrage optimiert, erstellt keine zusätzliche Tabelle und arbeitet schneller, der Abfrageplan ist gemeinsam.
  • Die mehrstufige Funktion erstellt eine temporäre Tabelle (tabellarische Variable), wodurch normalerweise der Abfrageplan schlechter ist, Fehler bei der kardinalen Schätzung auftreten können und die Leistung sinkt.
-- INLINE CREATE FUNCTION dbo.InlineActiveOrders(@userId INT) RETURNS TABLE AS RETURN ( SELECT * FROM Orders WHERE UserId = @userId AND Status = 'Active' ); -- Mehrstufige CREATE FUNCTION dbo.MultiActiveOrders(@userId INT) RETURNS @result TABLE (...) AS BEGIN INSERT INTO @result SELECT ... -- Logik RETURN END

Geschichte

Projekt: Finanzanalyse. Wir verwendeten skalare UDFs im SELECT-Teil eines Berichts über eine große Datenmenge: SELECT Amount, dbo.CalcTax(Amount, Type) FROM Transactions. Die Abfrage dauerte 5-10 Minuten aufgrund der zeilenweisen Verarbeitung der UDF. Wir schrieben es auf eingebautes CASE um: die Zeit reduzierte sich auf Sekunden.


Geschichte

Projekt: E-Commerce. Zur Suche nach Benutzerwarenkörben verwendeten wir mehrstufige tabellarische Funktionen, bei denen die Filterlogik in mehreren Schritten auftrat. Es stellte sich heraus, dass SQL keinen optimalen Plan erstellt und Scans durchführt, selbst wenn nur ein Element benötigt wird. Der Ersatz durch eine INLINE-Funktion beschleunigte die Abfragen sofort um das 50-Fache.


Geschichte

Projekt: CRM. Wir verlagerten die Geschäftslogik zur Gewährung von Boni in eine komplexe UDF. Nach ein paar Monaten stellten wir fest, dass sich die Geschäftsformeln geändert hatten, und es schwierig war, die Funktion zu aktualisieren, da sie eng mit den Daten verbunden war. In einem iterativen Produkt führte die UDF zu hohen Kosten für die Koordination von Änderungen zwischen Backend und DB.