如果我有这样的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
答案 0 :(得分:6)
将为a
中的每一行调用它。我不知道任何可以仅针对唯一输入调用该函数的优化。 如果性能是一个问题你可以创建一个具有不同输入值的临时表,并在你的加入中使用thoce结果,但我只会这样做它是一个问题 - 不要假设它是一个问题,并且不必要地混乱你的查询。
答案 1 :(得分:1)
如果将函数声明为模式绑定,则可以为每个唯一的情况运行一个。这要求函数是确定性的,并且对于给定的输入始终具有相同的输出。
CREATE FUNCTION dbo.fn_something (@id INT)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
RETURN @id
END
GO