Bonjour,

Je révise le code d'un développeur junior et je vois cette fonction:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ALTER FUNCTION [dbo].[RM_GetAvgDaysToPay] 
(
	-- Add the parameters for the function here
	@CompanyID int
)
RETURNS float
AS
BEGIN
	-- Declare the return variable here
	DECLARE @AvgDaysToPay float
 
	-- Add the T-SQL statements to compute the return value here
	DECLARE @Ansonia float
	DECLARE @Freight float
 
	SET @Ansonia = (SELECT TOP(1) aci.AvgDaysToPay FROM AnsoniaCreditInfo aci INNER JOIN CompanyDocketNumbers cdn ON aci.DocketPrefix = cdn.Prefix AND aci.DocketNumber = cdn.DocketNumber WHERE cdn.CompanyID = @CompanyID AND cdn.Purpose IN (1,3) ORDER BY cdn.Purpose)
 
	SET @Freight = (SELECT TOP(1) ci.AvgDaysToPay FROM CreditInformation ci INNER JOIN CompanyDocketNumbers cdn ON ci.DocketPrefix = cdn.Prefix AND ci.DocketNumber = cdn.DocketNumber WHERE cdn.CompanyID = @CompanyID AND ci.DocketNumber IS NOT NULL AND ci.DocketPrefix IS NOT NULL AND cdn.Purpose IN (1,3) ORDER BY cdn.Purpose)
 
	SET @AvgDaysToPay =
		CASE
			WHEN @Ansonia IS NULL AND @Freight IS NULL THEN NULL
			WHEN @Ansonia IS NOT NULL AND @Freight IS NOT NULL THEN CONVERT(float,(@Ansonia + @Freight)) / 2
			WHEN @Ansonia IS NOT NULL THEN @Ansonia
			WHEN @Freight IS NOT NULL THEN @Freight
		END
 
	-- Return the result of the function
	RETURN @AvgDaysToPay
 
END
Je me dis, plutôt que de lancer 2 requêtes et placer des valeurs en mémoire, je vais faire un seule et unique requête:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ALTER FUNCTION [dbo].[RM_GetAvgDaysToPay2] 
(
	-- Add the parameters for the function here
	@CompanyID int
)
RETURNS float
AS
BEGIN
	RETURN 
	(	SELECT TOP 1 CASE
					WHEN aci.AvgDaysToPay IS NULL OR ci.AvgDaysToPay IS NULL THEN (ISNULL(aci.AvgDaysToPay, 0) + ISNULL(ci.AvgDaysToPay, 0))
					ELSE (aci.AvgDaysToPay + ci.AvgDaysToPay) / 2
				END AS AvgValue
		FROM CompanyDocketNumbers cdn 
		LEFT JOIN AnsoniaCreditInfo aci ON cdn.DocketNumber = aci.DocketNumber AND cdn.Prefix = aci.DocketPrefix
		LEFT JOIN CreditInformation ci ON cdn.DocketNumber = ci.DocketNumber AND cdn.Prefix = ci.DocketPrefix
		WHERE cdn.CompanyID = @CompanyID
		AND cdn.Purpose IN (1,3) 
		ORDER BY cdn.Purpose)
 
END
Je lance les fonctions côte-à-côte en utilisant les bon vieux:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
SET STATISTICS IO ON
SET STATISTICS TIME ON
1 - Les deux plans d'exécution sont identiques
2 - Les statistiques de TIME et IO sont à toute fin pratique semblables

Mon environnement:

Instance SQL Server 2008R2
Base en mode 90 (2005)

Ma question:

Est-ce que SQL Server arrive à optimiser le code des fonctions (et procédure stockées) à un point tel qu'il peut joindre deux requêtes distinctes en une seule?

Ou bien c'est mon optimisation 'manuelle' qui n'est pas bonne?

Je travaille avec MSSQL depuis la version 7 et j'ai peut-être des habitudes d'optmisation qui sont devenue superflues depuis.

Merci de m'éclairer à ce sujet.

Aussi, si vous avez des sources intéressantes sur la façon sont MSSQL compile les fonctions et l'évolution de ce processus depuis la version 7, j'apprécierais énormément.