当select执行计算时,提高SQL性能

时间:2010-01-15 16:41:35

标签: sql sql-server sql-server-2005 performance

在下面的查询中,将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

4 个答案:

答案 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通常会更好。像我上面使用的派生表的执行计划中显示的“恒定扫描”将始终具有微不足道的成本。这个成本远远低于涉及磁盘访问的几乎任何数量的读取。