4

一只忙碌的猫

我使用 AdventureWorks2012 并进行测试。还有我的问题:为什么 SELECT 语句的性能直接低于表值函数。我只将 SELECT statemnt 放入表值函数和完全相反的性能。

CREATE FUNCTION [dbo].[atest1]
(
    @iBusinessEntityID  INT
)
RETURNS @t TABLE
(
    [BusinessEntityID]  INT
  , [NationalIDNumber]  NVARCHAR(15)
  , [JobTitle]          NVARCHAR(50)
)
AS
    BEGIN
        INSERT INTO @t
               SELECT 
                   [e].[BusinessEntityID]
                 , [e].[NationalIDNumber]
                 , [e].[JobTitle]
               FROM [HumanResources].[Employee] [e]
               INNER JOIN [Person].[Person] [p]
                    ON [p].[BusinessEntityID] = [e].[BusinessEntityID]
               WHERE [e].[BusinessEntityID] = @iBusinessEntityID;
        RETURN;
    END;

--TEST PERFORMANCE
SELECT 
    *
FROM [dbo].[atest1](5);
GO
SELECT 
    [e].[BusinessEntityID]
  , [e].[NationalIDNumber]
  , [e].[JobTitle]
FROM [HumanResources].[Employee] [e]
INNER JOIN [Person].[Person] [p]
     ON [p].[BusinessEntityID] = [e].[BusinessEntityID]
WHERE [e].[BusinessEntityID] = 5;
4

2 回答 2

7

这里的问题是估计的计划SSMS经常显示错误的百分比,在UDFs 的情况下它几乎总是做错了。

cost percentage是与其他操作相比的操作的估计成本,但在UDF SSMS不检查 UDF 内部的情况下。

UDF在我的服务器上创建了你的并添加了文本 a GUID,所以我可以轻松地返回这个 UDF 的计划:

CREATE FUNCTION [dbo].[atest1] (@iBusinessEntityID int)
RETURNS @t TABLE(BusinessEntityID int,NationalIDNumber nvarchar(15),JobTitle nvarchar(50)) AS
BEGIN
INSERT INTO @t /*3C6A985B-748B-44D4-9F76-1A0866342728*/ -- HERE IS MY GUID
SELECT e.BusinessEntityID, e.NationalIDNumber, e.JobTitle
FROM HumanResources.Employee e INNER JOIN Person.Person p ON p.BusinessEntityID = e.BusinessEntityID
WHERE e.BusinessEntityID = @iBusinessEntityID
RETURN
END

现在我执行这个函数并以这种方式检索它的计划:

select p.query_plan
from sys.dm_exec_cached_plans cp
     cross apply sys.dm_exec_sql_text(cp.plan_handle) t
     cross apply sys.dm_exec_query_plan(cp.plan_handle) p
where cp.objtype = 'Proc'
      and t.text like '%3C6A985B-748B-44D4-9F76-1A0866342728%'

我检查了这个计划,它和你的“直接陈述”的计划完全一样。它的SELECT部分是相同的,但是在主计划INSERT中的表变量中也有它。scan所以你可以清楚地看到你的UDF的成本不能更低,它等于“直接声明”成本加上INSERT成本加上表可变scan成本。

在此处输入图像描述

在这种情况下,表很小并且只有一个 UDF 调用,因此您无法注意到执行时间的差异,但是如果您创建一个循环执行您的“直接语句”更多次并调用 UDF 更多次,您可能会看到执行时间差,而且“直接语句”会更快。但无论如何SSMS都会坚持降低成本。UDF

于 2019-01-08T09:40:23.133 回答
2

通常,函数的行为比直接查询差,但在这种情况下,对于预定义为函数的某些内容,系统可能会存储更好的计划。在这种情况下,对于系统正在执行表扫描的功能,有时在 AdventureWorks DB 的小表上,它可能比按索引搜索更好。

此外,在您的示例中,该函数只有一次调用。降低函数性能的原因尤其是当您在查询中重复调用标量函数(提供的示例用于表函数)时。

于 2019-01-08T08:25:01.067 回答