【发布时间】:2011-08-02 20:26:12
【问题描述】:
我使用的是 SQL Server 2008R2。我编写了以下表值 UDF,它接受标量值 this 或 that 或两者都作为参数,并返回包含列 ID、this 和 that 的表。当我从复杂查询中调用此函数时,我看到了糟糕的性能,但在简单查询中调用它时却没有。我想知道是否有人对我正在做的事情有任何想法,这会减慢速度。函数定义如下:
CREATE function dbo.fn_getThisThat (@this nvarchar(255), @that nvarchar(255))
RETURNS TABLE
RETURN
SELECT These.this, Those.that, COALESCE(These.ID, Those.ID) as ID
FROM
(
SELECT col1 as ‘this’, value1, value2, ID
FROM (
SELECT t1.col1, t1.col2, t1.col3, t2.col1
FROM t1
JOIN t2
ON t1.col1 = t2.col1
WHERE t2.col2 = ‘this’
AND t1.col1 in (‘value1’, ‘value2’)
) SOURCE
PIVOT (
MAX(t1.col3) FOR t1.col1 in (value1, value2)
) AS pvt
) These
JOIN
(
SELECT t1.col1, t1.col2, t2.col1, t3.ID
FROM t3
JOIN t1
ON t3.col1 = t1.col1
JOIN t2
ON t2.col1 = t1.col1
WHERE t3.col3 = ‘value3’
AND t1.col3 = ‘value1’
AND t2.col3 = ‘value2’
) Those
WHERE that = @that
OR this = @this
在传递标量参数时,以下语句的处理速度非常快(
SELECT * FROM dbo.fn_getThisThat(scalarValue, null)
或者在一个相对简单的查询中,例如:
SELECT t1.col1, t1.col2, fn.This
FROM t1
CROSS APPLY dbo.fn_getThisThat(t1.col3, null)
...但是当在这样的更复杂的查询中调用时(在伪代码中:如果信息不足,请告诉我),它会滞后(从 ~1 秒到 ~2:30 秒的处理时间):
DECLARE @table (a, b, c)
INSERT @table (a, b, c)
SELECT (values)
SELECT t1.c1, t1.c2, t1.c3
FROM
(
SELECT a.c1, COUNT(fn.That) as c2, COUNT(a.c2) as c3
FROM a
JOIN b ON (join terms)
CROSS APPLY dbo.fn_getThisThat(a.c2, null) fn
WHERE a.c1 IN (SELECT a FROM @table)
GROUP BY a.c1
) t1
有人对我在第二个查询中降低速度的方法有什么建议吗?我将函数更改为接受数组而不是标量参数,但这消除了我交叉应用的能力(在最后一个代码片段中)。据我从查询分析器可以看出,性能损失来自我的函数的交叉应用。我以为我不会遇到 RBAR,因为我的 UDF 不是多语句,但也许我错了……?
编辑: 还有一件事:查询执行计划显示函数本身对批处理的贡献只有 2%;较大的查询贡献了 98%,但其大部分成本来自索引搜索和表扫描,而不是来自并行性。这让我觉得,也许函数调用并不是查询迟缓的原因,而是一些涉及的表缺乏索引(不幸的是,我对添加指数。)。我在没有调用函数的情况下运行了查询,表扫描和索引搜索仍然显示很高,但查询在大约 8 秒内完成。那么,我们回到函数...?
【问题讨论】:
标签: sql-server inline sql-server-2008-r2 user-defined-functions