Scalar Valued Functions sind ja super toll zu handhaben, aber ein Problem haben sie. Es ist keine parallele Verarbeitung mehr möglich. - Leider; der SQL Server schaltet sofort auf 1 Prozessor, sobald eine Scalar Valued Function beteiligt ist.

In der Folge werde ich zeigen, dass unter Umständen eine Inline Tabled Valued Function als Nested Loop oder mittels cross apply verwendet besser und schneller ist, als die Scalar Valued Function.

Aber selbstverständlich hat die Scalar Valued Function auch ihre Daseinsberechtigung! - ich will diese nicht schlecht machen.

Als Beispiel folgende 2 Aufrufe - SVF/TVF findet man hier

Verwendung von Scalar Valued Function

select SalesOrderID, dbo.SVF_Ostersonntag (a.ModifiedDate) as Ostern
from Sales.SalesOrderDetail a
inner join Sales.SpecialOffer b on a.SpecialOfferID = b.SpecialOfferID
inner hash /* hier hash, damit SQL-Server gezwungen wird parallel zu arbeiten */ join
  Production.Product d on a.ProductID = d.ProductID


Verwendung von Table Valued Function

 

select SalesOrderID, (Select Ostersonntag from dbo.TVF_Ostersonntag (a.ModifiedDate)) as Ostern
from Sales.SalesOrderDetail a
inner join Sales.SpecialOffer b on a.SpecialOfferID = b.SpecialOfferID
inner hash join Production.Product d on a.ProductID = d.ProductID

bzw.

select SalesOrderID, c.Ostersonntag as Ostern
from Sales.SalesOrderDetail a
inner join Sales.SpecialOffer b on a.SpecialOfferID = b.SpecialOfferID
inner hash join Production.Product d on a.ProductionID = d.ProductID
cross apply dbo.TVF_Ostersonntag (a.ModifiedDate) c

und der Erfolg:

CPU time = 5657 ms,  elapsed time = 6162 ms.

CPU time = 4467 ms,  elapsed time = 4312 ms.

und dann noch die beiden Execution Pläne, die es noch deutlicher zeigen

 

 

 und hier folgt selbstverständlich noch der Aufruf der SVF im Execution Plan (aber das ist ja nicht weiter interessant, da es hier um die nicht vorhandene Parallelität geht)

 

 

 hier zu sehen, die Parallelverarbeitung

Die Erklärung dafür (zumindest, warum es bei einer TVF noch parallel geht), ist, dass der SQL-Server die TVF komplett auflöst und den Syntax als ganz "banales" Select hinschreibt. Mittels set showplan_text on mache ich mir das sichtbar:

|--Compute Scalar(DEFINE:([Expr1019]=CASE WHEN ((((21)+((19)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))%(19))+(((15)+((3)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(3))/(4))-((8)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(13))/(25)))%(30))-((((19)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))%(19))+(((15)+((3)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(3))/(4))-((8)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(13))/(25)))%(30))/(29)+((((19)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))%(19))+(((15)+((3)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(3))/(4))-((8)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(13))/(25)))%(30))/(28)-(((19)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))%(19))+(((15)+((3)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(3))/(4))-((8)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(13))/(25)))%(30))/(29))*((datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))%(19))/(11))))+((7)-((((21)+((19)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))%(19))+(((15)+((3)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(3))/(4))-((8)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(13))/(25)))%(30))-((((19)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))%(19))+(((15)+((3)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(3))/(4))-((8)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(13))/(25)))%(30))/(29)+((((19)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))%(19))+(((15)+((3)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(3))/(4))-((8)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(13))/(25)))%(30))/(28)-(((19)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))%(19))+(((15)+((3)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(3))/(4))-((8)*(datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))/(100))+(13))/(25)))%(30))/(29))*((datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a].[ModifiedDate],0))%(19))/(11))))-((7)-((datepart(year,CONVERT_IMPLICIT(date,[AdventureWorks].[Sales].[SalesOrderDetail].[ModifiedDate] as [a..


|--Parallelism(Gather Streams)