【发布时间】:2009-02-03 04:21:12
【问题描述】:
我的系统进行了一些非常繁重的处理,我一直在攻击性能,以便让我能够在更短的时间内运行更多的测试运行。
在很多情况下,UDF 必须被调用,比如说 500 万行(我几乎认为没有办法绕过它)。
好吧,事实证明,有一种方法可以解决这个问题,当 UDF 被一组比总行集小一些的不同参数调用时,它可以显着提高性能。
考虑一个接受一组输入并根据复杂逻辑返回结果的 UDF,但对于超过 5m 行的输入集,只有 100,000 个不同的输入,因此它只会产生 100,000 个不同的结果元组(我的特殊情况从利率到复杂的代码分配不等,但它们都是离散的 - 这种技术的基本点是,您可以通过运行 SELECT DISTINCT 来简单地确定该技巧是否有效。
我发现通过这样做:
INSERT INTO PreCalcs
SELECT param1
,param2
,dbo.udf_result(param1, param2) AS result
FROM (
SELECT DISTINCT param1, param2 FROM big_table
)
当 PreCalcs 被适当索引时,它与:
SELECT big_table.param1
,big_table.param2
,PreCalcs.result
FROM big_table
INNER JOIN PreCalcs
ON PreCalcs.param1 = big_table.param1
AND PreCalcs.param2 = big_table.param2
您将获得巨大的性能提升。显然,仅仅因为某些东西是确定性的,并不意味着 SQL Server 正在缓存过去的调用并重新使用它们,正如人们可能认为的那样。
您唯一需要注意的是允许 NULL 的位置,然后您需要仔细修复您的联接:
SELECT big_table.param1
,big_table.param2
,PreCalcs.result
FROM big_table
INNER JOIN PreCalcs
ON (
PreCalcs.param1 = big_table.param1
OR COALESCE(PreCalcs.param1, big_table.param1) IS NULL
)
AND (
PreCalcs.param2 = big_table.param2
OR COALESCE(PreCalcs.param2, big_table.param2) IS NULL
)
希望这会有所帮助,欢迎使用 UDF 或重构查询以提高性能的任何类似技巧。
我想问题是,为什么需要像这样的手动缓存——服务器不知道函数是确定性的吗?如果它产生了如此大的差异,并且如果 UDF 如此昂贵,那么优化器为什么不直接在执行计划中进行呢?
【问题讨论】:
-
我想问题是,为什么需要像这样的手动缓存 - 这不是服务器知道函数是确定性的吗?如果它产生了如此大的差异,并且如果 UDF 如此昂贵,那么优化器为什么不直接在执行计划中进行呢。
标签: sql sql-server performance user-defined-functions