是一个标量数据库函数,在每个不同的输入集中调用一次或每行调用一次?

时间:2015-03-23 17:36:04

标签: sql sql-server tsql

如果我有这样的sql语句:

select * 
from tableA a
inner join tableB b on dbo.fn_something(a.ColX) = b.ColY

如果您假设tableA中有5行与ColX具有相同的值,dbo.fn_something()将使用该值调用5次或仅调用一次?

显然,这是一个微不足道的例子,但我对在更复杂的情况下考虑性能的目的感兴趣。

更新 谢谢@DStanley,根据你的回答,我进一步调查了。在下面的SQL上使用SQL Profiler与SP:StmtStarting事件说明了会发生什么。即如你所说:函数将在连接中的每一行被调用一次。

原始问题中有一个额外的联接。

create table tableA 
( id int ) 

create table tableB
( id_a int not null 
, id_c int not null 
) 

create table tableC
( id int ) 

go 
create function dbo.fn_something( @id int ) 
returns int 
as 
begin 
    return @id
end 
go 

-- add test data

-- 5 rows:
insert into tableA (id) values (1), (2), (3), (4), (5) 
-- 5 rows:
insert into tableC (id) values (101), (102), (103), (104), (105) 
-- 25 rows:
insert into tableB (id_a, id_c) select a.id, c.id from tableA a, tableC c

go 

-- here dbo.fn_something() is called 25 times: 
select * 
from tableA a
inner join tableB b on a.id = b.id_a
inner join tableC c on c.id = dbo.fn_something(b.id_c)

-- here dbo.fn_something() is called just 5 times, 
-- as the 'b.id_c < 102' happens to be applied first.
-- That's likely to depend on whether SQL thinks it's 
-- faster to evaluate the '<' or the function. 
select * 
from tableA a
inner join tableB b on a.id = b.id_a
inner join tableC c on c.id = dbo.fn_something(b.id_c) and b.id_c < 102

go

drop table tableA ; 
drop table tableB; 
drop table tableC; 
drop function dbo.fn_something;
go 

2 个答案:

答案 0 :(得分:6)

将为a中的每一行调用它。我不知道任何可以仅针对唯一输入调用该函数的优化。 如果性能是一个问题你可以创建一个具有不同输入值的临时表,并在你的加入中使用thoce结果,但我只会这样做它是一个问题 - 不要假设它是一个问题,并且不必要地混乱你的查询。

答案 1 :(得分:1)

如果将函数声明为模式绑定,则可以为每个唯一的情况运行一个。这要求函数是确定性的,并且对于给定的输入始终具有相同的输出。

CREATE FUNCTION dbo.fn_something (@id INT)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
    RETURN @id
END
GO