Ma réponse en conserve:
Il y a une idée fausse qui ont UDFs effet négatif sur la performance. En tant que déclaration générale, ce n'est tout simplement pas vrai. En fait, les fonctions définies par l'utilisateur (UDF) en ligne sont en fait des macros - l'optimiseur est très capable de réécrire des requêtes les impliquant ainsi que de les optimiser. Cependant, les fonctions UDF scalaires sont généralement très lentes. Je vais donner un petit exemple.
Pré-requis
Voici le script pour créer et remplir les tables:
CREATE TABLE States(Code CHAR(2), [Name] VARCHAR(40), CONSTRAINT PK_States PRIMARY KEY(Code))
GO
INSERT States(Code, [Name]) VALUES('IL', 'Illinois')
INSERT States(Code, [Name]) VALUES('WI', 'Wisconsin')
INSERT States(Code, [Name]) VALUES('IA', 'Iowa')
INSERT States(Code, [Name]) VALUES('IN', 'Indiana')
INSERT States(Code, [Name]) VALUES('MI', 'Michigan')
GO
CREATE TABLE Observations(ID INT NOT NULL, StateCode CHAR(2), CONSTRAINT PK_Observations PRIMARY KEY(ID))
GO
SET NOCOUNT ON
DECLARE @i INT
SET @i=0
WHILE @i<100000 BEGIN
SET @i = @i + 1
INSERT Observations(ID, StateCode)
SELECT @i, CASE WHEN @i % 5 = 0 THEN 'IL'
WHEN @i % 5 = 1 THEN 'IA'
WHEN @i % 5 = 2 THEN 'WI'
WHEN @i % 5 = 3 THEN 'IA'
WHEN @i % 5 = 4 THEN 'MI'
END
END
GO
Lorsqu'une requête impliquant une UDF est réécrite comme une jointure externe.
Tenir compte de la requête suivante:
SELECT o.ID, s.[name] AS StateName
INTO dbo.ObservationsWithStateNames_Join
FROM dbo.Observations o LEFT OUTER JOIN dbo.States s ON o.StateCode = s.Code
/*
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 1 ms.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Observations'. Scan count 1, logical reads 188, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'States'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 187 ms, elapsed time = 188 ms.
*/
et le comparer à une requête impliquant une table en ligne évalués UDF:
CREATE FUNCTION dbo.GetStateName_Inline(@StateCode CHAR(2))
RETURNS TABLE
AS
RETURN(SELECT [Name] FROM dbo.States WHERE Code = @StateCode);
GO
SELECT ID, (SELECT [name] FROM dbo.GetStateName_Inline(StateCode)) AS StateName
INTO dbo.ObservationsWithStateNames_Inline
FROM dbo.Observations
deux son plan d'exécution et ses coûts d'exécution sont les mêmes - la L'optimiseur l'a réécrit comme une jointure externe. Ne sous-estimez pas la puissance de l'optimiseur!
Une requête impliquant une UDF scalaire est beaucoup plus lent.
Voici une UDF scalaire:
CREATE FUNCTION dbo.GetStateName(@StateCode CHAR(2))
RETURNS VARCHAR(40)
AS
BEGIN
DECLARE @ret VARCHAR(40)
SET @ret = (SELECT [Name] FROM dbo.States WHERE Code = @StateCode)
RETURN @ret
END
GO
Il est clair que la requête en utilisant cette UDF fournit les mêmes résultats, mais il a un plan d'exécution différent et il est considérablement plus lent:
/*
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 3 ms.
Table 'Worktable'. Scan count 1, logical reads 202930, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Observations'. Scan count 1, logical reads 188, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 11890 ms, elapsed time = 38585 ms.
*/
Comme vous vu, l'optimiseur peut réécrire et optimiser les requêtes impliquant des UDF de table en ligne. D'autre part, les requêtes impliquant des UDF scalaires ne sont pas réécrites par l'optimiseur - l'exécution de la dernière requête inclut un appel de fonction par ligne, ce qui est très lent. Copié à partir here
La meilleure pratique serait de ne pas utiliser des fonctions pour des raisons de sécurité. – Woot4Moo