udf使用的SQL优化视图

时间:2011-11-23 20:56:09

标签: sql sql-server-2005 optimization

数据库:SQL Server 2005

我正在使用一个使用COALESCE函数创建逗号分隔列表的函数。

ALTER FUNCTION [dbo].[func_Codes](@CustID int, @GroupID int)
returns varchar(1000) as
BEGIN
    DECLARE @List varchar(1000)

    SELECT @List = COALESCE(@List + ',', '') + Code
    FROM dbo.vw_CustBillingInfo 
    WHERE dbo.vw_CustBillingInfo.CustID = @CustID
        AND dbo.vw_CustBillingInfo.GroupID = @GroupID

    RETURN @List
END

它调用的视图使用以下设置:

SELECT <columns>
FROM (SELECT <columns>
      FROM Customer
      INNER JOIN Codes ON dbo.GetRootCode(Customer.Code) = Codes.SpecialCode 
      OR (IsNumeric(Customer.Code) = 0 AND Substring(Customer.Code,2,3) = Codes.SpecialCode)

      UNION

      SELECT <columns>
      FROM Customer
      INNER JOIN Codes ON dbo.GetRootCode(Customer.Code2) = Codes.SpecialCode 
         OR (IsNumeric(Customer.Code2) = 0 AND Substring(Customer.Code2,2,3) = Codes.SpecialCode)

      UNION

      <Repeat a few more similar unions>

dbo.GetRootCode(code)标量函数对列执行一些子字符串操作,以提取varchar列的特殊部分。

如果我从视图中取出查询,我可以通过创建临时表并为每个使用的代码存储GetRootCode(Customer.Code), IsNumeric(Customer.Code), Substring(Customer.Code,2,3),等的值来提高性能。这似乎不是最好的方法,但它表明可以完成优化。此外,视图无论如何都不能使用临时表。

我没有创建逗号分隔列表的功能,而是尝试了xml变体,我在网上看到了多个地方。

STUFF((
    SELECT ','+Code FROM dbo.vw_CustBillingInfo WHERE dbo.vw_CustBillingInfo.CustID = C.CustID AND dbo.vw_CustBillingInfo.GroupID = C.GroupID FOR XML PATH('')
        ), 1, 1, '')

然而,虽然这有效,但性能相当糟糕。它为查询的执行时间增加了大约20到30秒

这使我回到尝试直接优化视图以获得更好的性能。 IO统计信息显示视图的第一个选择:

(20 row(s) affected)
Table 'Worktable'. Scan count 1, logical reads 42920, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Customer'. Scan count 1, logical reads 269, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Codes'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

这需要一秒钟才能执行。将其添加到所有联合上,然后在执行路径上调用此视图两次,并且时间大大增加。

我坚持使用优化视图的INNER JOIN的最佳方法来提高速度并减少所需的IO。任何建议都将不胜感激。

1 个答案:

答案 0 :(得分:1)

您每JOIN使用两个不可搜索的JOIN条件。

因此,根据您的实施情况,每个JOIN至少可以进行一次表扫描。

真正简短的回答是:

  • 不要在{UDF
  • JOIN
  • 请勿JOIN使用任何其他功能(例如SUBSTRING)。

几乎没有办法优化这一点。 SQL不知道输出将运行该函数的内容,因此它会针对每一行运行它。