Undvik funktioner på kolumner

När man jobbar med sql-server så skall man undvika att köra funktionerna på kolumnen. Istället skall man försöka räkna om värdet innan frågan ställs.

Vi kan exempelvis tänka oss ett scenario där man har en kolumn med datum som representerar födelsedatum. Nu vill vi hämta ut alla personer från den tabellen som är 50 år. 

Vi kan då tänka oss att man skapar en funktion som tar emot ett fördelsedatum och returnerar ett heltal med aktuell ålder för det. Problemet med denna lösningen är att sql-server då inte kan använda det index som möjligen finns på födelsedatumskolumnen. Detta eftersom sql-server omöjligen kan veta vad funktionen gör och därför måste den scanna igenom hela tabellen och steg för steg plocka ut de poster som matchar värdet man önskar.

För att illustrera detta så skapar jag i mitt exempel nedan en funktion som inte gör något alls, den tar emot ett datum och returnerar det. Men trots detta så blir det genast en markant skillnad på prestanda.

CREATE FUNCTION dbo.DoNothing (@date date)
RETURNS date
AS
BEGIN
 return @date
END
GO
SELECT * FROM Users WHERE DateOfBirth = '1970-01-01'
--Table 'users'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SELECT * FROM Users WHERE dbo.DoNothing(DateOfBirth)= '1970-01-01'
--Table 'users'. Scan count 1, logical reads 3495, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Om vi vill hämta ut alla som är en viss ålder så skall vi alltså beräkna vilka datum som är det största respektive minsta som är möjligt för den åldern vi vill hämta.
Frågan skulle kunna se ut något i stil med
SELECT * FROM Users
WHERE DateOfBirth >= dbo.GetMinDateOfBirth(50)
AND DateOfBirth <= dbo.GetMaxDateOfBirth(50) -- [/sourcecode]

Kommentarer inaktiverade.

%d bloggare gillar detta: