【问题标题】:Function Efficiency功能效率
【发布时间】:2020-02-14 15:19:01
【问题描述】:

我是创建存储过程和函数的新手,我只是不明白为什么其中一个版本的运行速度比另一个快得多。这是一个在调用时只返回带有描述的字符串的函数。原始函数依赖于提供大约 10 个变量(版本在大约 4 秒内运行)。我想将其缩减为单个变量(运行时间较长的版本)。

变量声明下面的代码是相同的,唯一的区别是我试图从函数本身的适当位置提取变量,而不是在查询端提供它们。

即dbo.cf_NoRateReason(V1) 作为 ReasonCode 而不是 dbo.cf_NoRateReason(V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12)

如果我没有提供足够的信息,我先道歉,正如我所说的,新功能/存储过程。

此版本运行时间约为 2.5 分钟

    declare @Agencyid int
    declare @ServiceCode varchar(10)
    declare @Mod1 varchar(2)=null
    declare @Mod2 varchar(2)=null
    declare @Mod3 varchar(2)=null
    declare @Mod4 varchar(2)=null
    declare @POS int
    declare @ServiceDate datetime
    declare @ProvType varchar(1)
    declare @PayerID int
    declare @BirthDate datetime
    declare @RenderingStaffID int 
    declare @SupervisingStaffID int 
    Select @Agencyid=s.agencyid, @ServiceCode = ServiceCode, 
           @Mod1 = ModifierCodeId, @Mod2 = ModifierCodeId2, 
           @Mod3 = ModifierCodeId3, @Mod4 = ModifierCodeId4,
           @POS=PlaceOfServiceId, @ServiceDate = ServiceDate, 
           @RenderingStaffId=isnull(dbo.GetProviderStaffId('S',s.ServiceTransactionId,'82'),0),
           @SupervisingStaffId=isnull(dbo.GetProviderStaffId('C',ClaimId,'DQ'),0),
           @ProvType=s.servicetype, @Payerid=pmt.payerid,
           @BirthDate=i.birthdate
      From ServiceTransaction s
            join individual i on s.servicetransactionid = i.individualid
            join pmtadjdetail pmt on s.servicetransactionid = pmt.servicetransactionid

    declare @Result Varchar(100) = ''
    declare @Age int = dbo.getageatservicedate(@birthdate, @ServiceDate)
    declare @ModString varchar(8) = dbo.sortmodifiers(@Mod1, @Mod2, @Mod3, @Mod4)
    declare @DirectSupervision int = (iif(@Mod1 in ('U1','U6','U7','U9','UA') 
        or @Mod2 in ('U1','U6','U7','U9','UA') 
        or @Mod3 in ('U1','U6','U7','U9','UA')
        or @Mod4 in ('U1','U6','U7','U9','UA'),1,0))

'************************************************************************************'
'This version takes about 4 seconds to run'
'************************************************************************************'
begin
    declare @Result Varchar(100) = ''
    declare @Age int = dbo.getageatservicedate(@birthdate, @ServiceDate)
    declare @RenderingStaffID int = dbo.getstaffid(@STID,'DQ')
    declare @SupervisingStaffID int = dbo.getstaffid(@STID,'82')
    declare @ModString varchar(8) = dbo.sortmodifiers(@Mod1, @Mod2, @Mod3, @Mod4)
    declare @DirectSupervision int = (iif(@Mod1 in ('U1','U6','U7','U9','UA') 
        or @Mod2 in ('U1','U6','U7','U9','UA') 
        or @Mod3 in ('U1','U6','U7','U9','UA')
        or @Mod4 in ('U1','U6','U7','U9','UA'),1,0))

【问题讨论】:

  • 您首先列出的版本没有过滤器没有 WHERE 子句)在它用来获取“参数”值的 SELECT 上它通常是通过了。您有效地获得了整个连接结果集,每个结果行的函数调用成本,并且只取最后一个结果的值。
  • 标量函数在最好的情况下对性能来说是可怕的。最好使用表值参数或内联表值函数。
  • 您的第一个查询中有一个以“选择 @Agencyid=s.agencyid, @ServiceCode = ServiceCode, ”等开头的查询,您可能想知道这需要多长时间
  • 谢谢Uueerdo,你也是个天才!这正是问题所在

标签: sql-server function processing-efficiency


【解决方案1】:

这种属于“错字”或简单的疏忽,但是....

当您无缘无故地发现性能差异如此之大(原始版本中也使用了这些功能)时,通常是您需要开始查找这些类型的错误:拼写错误、缺少条件、过于依赖智能感知/代码完成等不正确的条件......

将多个参数替换为可用于自动检索其他参数的参数时,请始终确保实际使用该参数。

您首先列出的版本在它用来获取通常传递的“参数”值的 SELECT 上没有过滤器(没有 WHERE 子句)。您有效地获得了整个连接结果集,每个结果行的函数调用成本,并且只取最后一个结果的值。

【讨论】:

    【解决方案2】:

    你是对的 - 唯一的区别是使用函数。请参阅similarquestions 已解决此问题。

    简而言之,函数将逐行执行,而查询端的代码将有其他选项,而不会对函数进行开销调用。 您可以将标量函数与模式绑定一起使用,并且 null 会返回 null 以获得更好的性能。

    对架构计划进行额外考虑会很有价值。这里还有连接和其他嵌入式逻辑,没有样本数据是不清楚的。

    【讨论】:

    • 他的查询开始'Select @Agencyid=s.agencyid, @ServiceCode = ServiceCode,' 似乎更有可能是问题所在,特别是正如 Uueerdo 指出的那样,它可能返回很多行,但是然后只保留碰巧返回的最后一行的值(实际上是其中任何一个)。
    • 谢谢,我会阅读你的建议。我正在使用与数据库中另一个标量值函数类似的过程,它比我的运行速度更快,我只是看不出我正在做的事情和其他函数正在做的事情之间的区别在设置变量方面,这似乎是挂断的地方。
    • 检查 Uueerdo 的评论 - 除非有单行表,否则第一个 proc 中的查询似乎返回多条记录 - 你肯定需要缩小到单行 - 隔离查询在 SSMS 窗口中,将其更改为 SELECT *,然后查看它获得了多少行
    • 卡托,你是个天才,我是个白痴。您是 100% 正确的,我没有将返回的数据集限制为单个记录(使用 @STID 变量)。它现在运行并运行在 1 秒而不是 4 秒!
    • @Cato 似乎是正确的;我将把它留给评论讨论,因为它是相关的。很抱歉造成误会。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 2013-04-28
    • 2020-10-16
    • 2019-11-26
    • 2020-09-12
    • 2019-03-10
    相关资源
    最近更新 更多