数据库: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。任何建议都将不胜感激。
答案 0 :(得分:1)
您每JOIN
使用两个不可搜索的JOIN
条件。
因此,根据您的实施情况,每个JOIN
至少可以进行一次表扫描。
真正简短的回答是:
JOIN
JOIN
使用任何其他功能(例如SUBSTRING
)。几乎没有办法优化这一点。 SQL不知道输出将运行该函数的内容,因此它会针对每一行运行它。