Dass der SQL Server 2014 mit seinen InMemory-Fähigkeiten einen erheblichen Performance-Boost in vielen praktischen Einsatzmöglichkeiten ermöglicht, haben wir bereits ausführlich dokumentiert.
Einer der Faktoren, die eine erhebliche Beschleunigung von InMemory-Abfragen ermöglichen, sind nativ kompilierte Stored Procedures (NCSPs). Diese bieten zwar eine erhebliche Beschleunigung, erlauben aber nur einen eingeschränkten Zugriff auf die reichhaltigen Funktionen von T-SQL. Wir möchten hier einen typischen Workaround für eine solche Einschränkung vorstellen.
Oftmals steht der Entwickler beim Schreiben von NCSPs vor der Fehlermeldung
The function ‚…‘ is not supported with natively compiled stored procedures.
Für viele mathematische Funktionen gibt es dabei elegante Workarounds. Zum Beispiel ist abs(@arg) = sqrt(power(@arg,2)).
Etwas komplizierter wird es bei Funktionen wie Ceil und Floor oder auch Sign, die abhängig vom Vorzeichen sind.
Da T-SQL keine CASE-Konstrukte in NCSPs erlaubt, müssen wir für das korrekte Verhalten an dieser Stelle mit TRY/CATCH-Konstrukten arbeiten. Die drei Funktionen Ceil, Floor und Sign lassen sich dann wie folgt umsetzen:
if OBJECT_ID('dbo.Mathtest') is not null drop procedure dbo.MathTest go create procedure dbo.MathTest(@arg numeric(10,2)) with native_compilation, schemabinding, execute as owner as begin atomic with (transaction isolation level = snapshot, language = N'English') declare @sign int declare @dump numeric(10,2) begin try select @sign = cast(@arg/SQRT(POWER(@arg,2)) as numeric(10,0)) end try begin catch -- division by zero means, @arg is zero select @sign = 0 end catch begin try select @dump = 1/(@sign*(@arg%1)) -- is our number integer or zero? -- nmber is not zero select cast(@arg-(@arg % 1) + (-1+@sign)*0.5 as int) as [floor], cast(@arg-(@arg%1) + (1+@sign)*0.5 as int) as [ceil], @sign as [sign] end try begin catch -- @arg is integer or zero! select @arg as [floor], @arg as [ceil], @sign as [sign] end catch end go
Die Tests zeigen das erwartete Verhalten der Funktionen:
declare @arg numeric(10,2) set @arg = -3.14 exec dbo.MathTest @arg select floor(@arg), ceiling(@arg)
liefert als Werte für Floor und Ceiling übereinstimmend -4 bzw. -3 und für @arg = 3.14 erhalten wir wie erwartet 3 und 4.
Welche Funktionen vermissen Sie, welche Workarounds haben Sie gefunden? Bitte teilen Sie Ihre Erfahrungen mit uns in den Kommentaren zu diesem Beitrag.