在下面的查询中,将case语句移动到UDF的性能更好吗?如果是这样的话?
SELECT id,
name,
case
when v1 = 'Y' then 'something'
when v2 = 'K' then 'something else'
when v3 is null then 'dont know'
else 'default'
end
from table
答案 0 :(得分:2)
不,我会像它一样离开它。使用UDF(通常)可以有一些 wierd side effects and limitations ,这个查询根本不能证明使用它们。 UDF性能应该不比从这个直接查询得到的好。
以下是相关博客文章:http://www.bennadel.com/blog/964-SQL-User-Defined-Functions-Are-Slower-Than-Inline-Logic.htm
答案 1 :(得分:1)
UDF通常比查询中的case语句执行得最差。但是对于大多数SQL,最好同时尝试并比较结果。
答案 2 :(得分:0)
如果您进入单独的UDF,它可能不会有任何影响。为了提高性能,Sql Server优化了这些类型的操作,无论如何,你的UDF可能会被“内联”。
答案 3 :(得分:0)
顺便说一句(抱歉,我不记得我在哪里读到这篇文章)优化器在使用case语句的“短”语法形式时有机会获得更好的执行计划。尽管最终简短形式只是语法糖,但它为优化器提供了一个暗示,即所有比较都是基于简单的简单而不涉及复杂的表达式。
您的案例陈述无法切换,因为您使用的是3个不同的列,v1,v2和v3。但是如果你使用所有相同的列,比如v1,那么这种修改有时会表现得更好:
SELECT
id,
name,
case Coalesce(v1, 'dont know')
when 'Y' then 'something'
when 'K' then 'something else'
when 'dont know' then 'dont know'
else 'default'
end
from table
好吧,也许这并不理想,因为空处理需要一些配置。我只想指出在某些情况下可以进行的优化,因为您正在寻找一般的优化提示。
对于它的价值,我完全同意UDF会表现更差。几乎普遍的内联提供了性能改进,因为它避免了进行调用和从调用返回所需的所有工作(除非优化器秘密地为您内联)。
在这种特定情况下的另一个想法是,您可以考虑使用带有完整文字值的派生表的连接:
SELECT
id,
name,
coalesce(x.result, 'dont know')
from
table t
left join (
select 'Y', 'something'
union all select 'K', 'something else'
union all select '%', 'default'
) x (value, result) on t.v1 like x.value
同样,由于我选择使用LIKE进行空值处理的方式,这可能并不完美。但是,它充分展示了这项技术。
补充要点:
测试始终是为了找出在任何情况下都能提供最佳性能的方法。填充一个满100,000或100万行的表,并使用分析器运行来捕获cpu,读取,写入和持续时间。更喜欢在较低持续时间内降低cpu /读数。
虽然执行计划通常是很好的指南,但不要完全信任执行计划成本,因为它们完全忽略了UDF的内部成本,并且不总是正确地公开cpu / read权衡。
如果它甚至可以避免少量读取,那么花一点点cpu通常会更好。像我上面使用的派生表的执行计划中显示的“恒定扫描”将始终具有微不足道的成本。这个成本远远低于涉及磁盘访问的几乎任何数量的读取。