标量用户定义函数内T-Sql查询的性能

时间:2015-11-17 06:27:45

标签: sql-server performance sql-function

我最近审核了一位同事的SQL Server函数(在SQL Server 2008中),他在标量用户定义函数中放置了T-SQL查询。然后在查询的Select子句中使用该函数。

我认为在函数内部进行查询会产生糟糕的性能,因为我假设返回的每一行都必须运行查询 - 即使该查询已经过优化以查询索引。

以下是我所谈论的一个例子:

create table [PERSON] (
ID int primary key,
FIRSTNAME NVARCHAR(100),
MIDDLENAME NVARCHAR(100) null,
LASTNAME NVARCHAR(100))
GO

INSERT INTO PERSON (ID, FIRSTNAME, MIDDLENAME, LASTNAME)
VALUES (1, 'BOB', 'M', 'BLUE')

INSERT INTO PERSON (ID, FIRSTNAME, MIDDLENAME, LASTNAME)
VALUES (2, 'VALERIE', 'J', 'GREEN')

INSERT INTO PERSON (ID, FIRSTNAME, MIDDLENAME, LASTNAME)
VALUES (3, 'SIMON', 'D', 'RED')

INSERT INTO PERSON (ID, FIRSTNAME, MIDDLENAME, LASTNAME)
VALUES (4, 'LIONEL', 'W', 'BROWN')
GO

-- Scalar Function with T-SQL
CREATE FUNCTION dbo.fn_FormatNameFromId(
            @pnPersonId int
            )
Returns nvarchar(300)
AS
Begin
    return (Select FIRSTNAME + ' ' + MIDDLENAME + ' ' + LASTNAME
        From PERSON
        Where ID = @pnPersonId)
End
go

-- Scalar Function without T-SQL
CREATE FUNCTION dbo.fn_FormatNameFromValues(
            @psFirstName nvarchar(100),
            @psMiddleName nvarchar(100),
            @psLastName nvarchar(100)
            )
Returns nvarchar(300)
AS
Begin
    return (@psFirstName + ' ' + @psMiddleName + ' ' + @psLastName)
End
go

-- T-SQL within function
select dbo.fn_FormatNameFromId(ID)
from PERSON

-- Pass values directly
select dbo.fn_FormatNameFromValues(FIRSTNAME, MIDDLENAME, LASTNAME)
FROM PERSON

当比较这两个选项的执行计划时,我发现两个函数的cpu或内存性能没有差别。即使在扩展测试以返回数万行时,也没有性能差异。

有人可以解释fn_FormatNameFromId不会导致性能下降的原因或原因吗?

2 个答案:

答案 0 :(得分:1)

就个人而言,我不是t-sql函数的忠实粉丝,所以我在SQL SERVER中尽可能地避免使用它们,

是的,我知道用户函数在编程方面有很多优点。

直接回答您的问题

  

当比较这两个选择的执行计划时,我可以   发现两者的CPU或内存性能没有差别   功能

我通常不会比较执行计划,以检查哪个计划更好,哪个更糟糕,因为这些成本仅基于估算值。

  

任何人都可以解释fn_FormatNameFromId不会导致的原因或原因   失去表现?

因为你还在处理很少的数据我测试了你的两个函数如下:

declare @a int=1
Declare @name varchar(50)
while (@a<99999)
Begin 
-- T-SQL within function
select @name = dbo.fn_FormatNameFromId(ID)
from PERSON
SET @a =@a+1
END

它在我的本地系统上运行了13秒

declare @a int=1
Declare @name varchar(50)
while (@a<99999)
Begin 

-- Pass values directly
select @name =dbo.fn_FormatNameFromValues(FIRSTNAME, MIDDLENAME, LASTNAME)
FROM PERSON
SET @a =@a+1
END

它在我的本地系统上运行了9秒

啊,我说我不喜欢功能,所以没有功能运行

declare @a int=1
Declare @name varchar(50)
while (@a<99999)
Begin 

-- Pass values directly


Select @name= FIRSTNAME + ' ' + MIDDLENAME + ' ' + LASTNAME
        From PERSON


SET @a =@a+1
END

并且在我的系统中以2秒钟的速度运行

请阅读以下文章

T-SQL User-Defined Functions: the good, the bad, and the ugly

答案 1 :(得分:1)

您可以看到+2147483648Estimated Execution Plan

之间的区别

您个人希望Actual Execution Plan能够按照屏幕截图所示工作: 来自查询1(聚簇索引扫描)的每一行的执行查询2(聚簇索引查找 - 或按ID查询子查询) Estimated Execution Plan

但是sql-server可以看到这些查询的整体模式,并将实际查询计划优化为一个简单的select dbo.fn_FormatNameFromId(ID) from PERSON,就像sql-server在第二个查询Clustered Index Scan中所做的那样。