有没有办法提高这个SQL函数的性能?

时间:2012-01-16 15:51:48

标签: sql performance stored-procedures user-defined-functions

我有一张类似

的表格
Event ID  Date       Instructor
1         1/1/2000    Person 1
1         1/1/2000    Person 2

现在我要做的是返回这些数据,以便每个事件都在一行上,而教师都在一个列中,并使用<br>标记'Person 1 <br> Person 2'

进行拆分

目前我这样做的方法是使用函数

CREATE FUNCTION fnReturnInstructorNamesAsHTML
(
    @EventID INT
)
RETURNS VARCHAR(max)
BEGIN

    DECLARE @Result VARCHAR(MAX)

    SELECT 
        @result = coalesce(@result + '<br>', '') + inst.InstructorName 
    FROM
        [OpsInstructorEventsView]   inst
    WHERE
        inst.EventID = @EventID

    RETURN @result


END

然后我的主存储过程将其称为

   SELECT 
        ev.[BGcolour], 
        ev.[Event] AS name, 
        ev.[eventid] AS ID, 
        ev.[eventstart], 
        ev.[CourseType], 
        ev.[Type], 
        ev.[OtherType], 
        ev.[OtherTypeDesc], 
        ev.[eventend], 
        ev.[CourseNo], 
        ev.[Confirmed], 
        ev.[Cancelled], 
        ev.[DeviceID] AS resource_id, 
        ev.Crew, 
        ev.CompanyName , 
        ev.Notes,
        dbo.fnReturnInstructorNamesAsHTML(ev.EventID) as Names
    FROM 
        [OpsSimEventsView] ev
    JOIN
        [OpsInstructorEventsView]   inst
    ON
        ev.EventID = inst.EventID 

这非常慢,我看着每次调用DB的时间是4秒。有没有办法让我提高功能的性能?它是一个相当小的功能,所以我不知道我能在这里做什么,而且我无法看到将COALESCE用于主程序的SELECT的方法。

非常感谢任何帮助,谢谢。

3 个答案:

答案 0 :(得分:1)

你可以尝试这样的事情。

SELECT 
    ev.[BGcolour], 
    ev.[Event] AS name, 
    ev.[eventid] AS ID, 
    ev.[eventstart], 
    ev.[CourseType], 
    ev.[Type], 
    ev.[OtherType], 
    ev.[OtherTypeDesc], 
    ev.[eventend], 
    ev.[CourseNo], 
    ev.[Confirmed], 
    ev.[Cancelled], 
    ev.[DeviceID] AS resource_id, 
    ev.Crew, 
    ev.CompanyName , 
    ev.Notes,
    STUFF((SELECT '<br>'+inst.InstructorName
           FROM [OpsInstructorEventsView]   inst
           WHERE ev.EventID = inst.EventID
           FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 4, '') as Names
FROM 
    [OpsSimEventsView] ev

不确定您在主查询中加入OpsInstructorEventsView的原因。我在这里删除它,但如果你需要,你可以再添加它。

答案 1 :(得分:0)

要注意的一些事项:

1)函数的开销使得调用成本很高,尤其是在可能返回数千行的查询的select语句中。它必须为它们中的每一个执行该功能。考虑将函数的行为合并到主存储过程中,SQL Server可以更好地利用其优化器。

2)由于您要在两个表中加入事件ID,请确保在这两个列上有索引。我希望你这样做,因为那些似乎都是主键列,但请确保。索引可以产生巨大的差异。

3)将您的coalesce调用转换为等效的case语句,以消除调用该函数的开销。

答案 2 :(得分:0)

是的,使其成为INLINE Table-Value SQL函数:

 CREATE FUNCTION fnReturnInstructorNamesAsHTML 
 (  @EventID INT  ) 
 RETURNS Table   
 As 
  Return

  SELECT  InstructorName + '<br>' result 
  FROM OpsInstructorEventsView
  WHERE EventID = @EventID 
  Go

然后,在您的SQL语句中,像这样使用它

SELECT    ]Other stuff],
    (Select result from dbo.fnReturnInstructorNamesAsHTML(ev.EventID)) as Names   
FROM OpsSimEventsView ev   
   JOIN OpsInstructorEventsView inst   
     ON  ev.EventID = inst.EventID    

我不清楚你在问题中显示的查询如何连接结果的一行中的多行数据,但问题是普通的UDF在使用时编译,在每次使用时都是如此,因此对于每一行在您的输出结果中,Query processopr必须再次重新编译UDF。对于“内联表值”UDF,这不是True,因为它在传递给SQL优化器(生成语句缓存计划的子系统)之前将sql折叠到外部sql中,因此UDF只编译一次。