2010-01-15 4 views
1

Je fais une requête CTE relativement complexe avec un appel de fonction scalaire coûteux défini par l'utilisateur. Les clauses where du CTE filtrent la plupart des données de table volumineuses et retournent un résultat relativement faible. Le calcul d'un champ coûteux n'est donc pas un problème s'il est calculé sur le jeu de résultats.Fonction coûteuse à l'intérieur d'un select imbriqué

Le serveur SQL fait du bon travail s'il n'évalue pas la colonne coûteuse, s'il n'est pas touché par l'un des prédicats dans les sous-requêtes CTE, il est évalué uniquement pour le jeu de résultats. La question est, est-ce que je peux compter sur ce bon comportement de l'optimiseur dans ce cas, ou les choses peuvent mal tourner quand le plan est reconstruit?

Voici un code de test.

use tempdb; 
go 
/****** Object: UserDefinedFunction [dbo].[expensive] Script Date: 01/15/2010 18:43:06 ******/ 
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[expensive]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT')) 
DROP FUNCTION [dbo].[expensive] 

go 
-- used to model expensive user defined function. 
-- inexpensive in case of @i = 1 
create function dbo.expensive(@i int) 
returns int 
as 
begin 
if(@i = 1) begin return @i; -- inexpensive in this case 
end; 
declare @N bigint 
declare @ret bigint 
set @N = 17; -- will generate a set of 2^N 

declare @tab table(num int); 

with gig as 
(
    select 1 as num 
    union all 
    select g.num + 1 as num from gig g 
    where g.num < @N 
    union all 
    select g.num + 1 as num from gig g 
    where g.num < @N 
) 
select @ret = count(num) from gig; 
return @ret; 
end 

go 

declare @tab table(i int); 

insert into @tab select 1 union select 2 union select 3; 

select CURRENT_TIMESTAMP; 

with source as 
(
-- some really complex stuff that has an expensive calcutated scalar 
select c.i, c.caclulated from @tab t 
join 
(select i, dbo.expensive(i) as caclulated from @tab) as c 
on t.i = c.i 
) 
select * from source where 
i = 1; -- this query is inexpensive, because do not touch anything but 1 

select CURRENT_TIMESTAMP; 

-- this one is expensive 
select dbo.expensive(2) 

select CURRENT_TIMESTAMP; 
+0

Je constate que le CTE que vous avez donné est un exemple, pas le vrai que vous utilisez. Pourriez-vous donner un aperçu de la réalité CTE et comment cela fonctionne? Pouvez-vous poster le code pour cela? Quel problème essayez-vous réellement de résoudre? Je pourrais répondre à propos des plans d'exécution, mais je soupçonne qu'il pourrait y avoir d'autres réponses qui pourraient vous aider. – ErikE

Répondre

Questions connexes