【问题标题】:Function Consuming High CPU in SQL Server 2017SQL Server 2017 中占用高 CPU 的函数
【发布时间】:2021-11-21 14:49:52
【问题描述】:

我在我们的客户端环境中遇到了一个消耗 CPU 的函数。

下面是查询。

CREATE function [dbo].[fnEncClaimType](@in_ApptOrEncId numeric(8),@in_bool_IsApptId numeric(2)) 
returns varchar(20)
as
begin 
    declare @returnVal varchar(20)
    set @returnVal = ''
    if @in_bool_IsApptId = 1 begin 
        SELECT TOP 1 @returnVal = CASE 
        WHEN BLH_PATINV_TEXT = 'AUTO' THEN 'Auto Accident' 
        WHEN BLH_PATINV_TEXT = 'EMPLOYER' THEN 'Employer' 
        WHEN BLH_PATINV_TEXT = 'PATCLM' THEN 'Self Pay' 
        WHEN BLH_PATINV_TEXT = 'PATINV' THEN 'Penalty Invoice' 
        WHEN BLH_PATINV_TEXT = 'PI' THEN 'Penalty Invoice' 
        WHEN BLH_PATINV_TEXT = 'INJURY' THEN 'Personal Accident' 
        WHEN BLH_PATINV_TEXT = 'PROF' THEN 'Professional' 
        WHEN BLH_PATINV_TEXT = 'TPA' THEN 'TPA' 
        WHEN BLH_PATINV_TEXT = 'UB04' THEN 'Institutional' 
        WHEN BLH_PATINV_TEXT = 'WORKCOMP' THEN 'Work Comp' 
        WHEN BLH_PATINV_TEXT = 'DMERC' THEN 'DMERC' ELSE '' 
        END FROM TRN_BILLING_HEAD,TRN_ENCOUNTERS 
        WHERE BLH_ENC_ID = ENC_ID 
        AND (BLH_APPT_ID = @in_ApptOrEncId OR ENC_APPT_ID = @in_ApptOrEncId) 
        AND BLH_BOOL_INACTIVE = 0 
        ORDER BY BLH_ID end 
    else begin 
        SELECT TOP 1 @returnVal = CASE 
        WHEN BLH_PATINV_TEXT = 'AUTO' THEN 'Auto Accident'
        WHEN BLH_PATINV_TEXT = 'EMPLOYER' THEN 'Employer' 
        WHEN BLH_PATINV_TEXT = 'PATCLM' THEN 'Self Pay' 
        WHEN BLH_PATINV_TEXT = 'PATINV' THEN 'Penalty Invoice'
        WHEN BLH_PATINV_TEXT = 'PI' THEN 'Penalty Invoice' 
        WHEN BLH_PATINV_TEXT = 'INJURY' THEN 'Personal Accident' 
        WHEN BLH_PATINV_TEXT = 'PROF' THEN 'Professional' 
        WHEN BLH_PATINV_TEXT = 'TPA' THEN 'TPA' 
        WHEN BLH_PATINV_TEXT = 'UB04' THEN 'Institutional' 
        WHEN BLH_PATINV_TEXT = 'WORKCOMP' THEN 'Work Comp' 
        WHEN BLH_PATINV_TEXT = 'DMERC' THEN 'DMERC' ELSE '' END 
        FROM TRN_BILLING_HEAD 
        WHERE BLH_ENC_ID = @in_ApptOrEncId AND BLH_BOOL_INACTIVE = 0 
        ORDER BY BLH_ID
    end

    return @returnVal 
end;

我检查了执行计划以检查索引,它正在使用适当的索引执行索引搜索。

任何人都可以建议优化此所需的任何查询级别更改。 我不是开发人员,因此很难检查任何查询级别的优化。

【问题讨论】:

  • 如果它像你说的那样使用适当的索引,它应该是即时的,因为它将使用这些索引返回一行。但是,如果您为外部查询中的每一行调用它,它应该很慢,因为它是多步的。将其重写为内联。
  • 一些好的格式(使用换行符和空格)确实不会在该对象的定义中出错。
  • 当我 确实 使这个看起来很好格式化时,几个 cmets: 1. 现在是 2021 年,为什么你 仍然 使用 1980 年的隐式 JOIN句法?它在 1992 中被显式连接语法所取代。 2. 这将不得不被解析为一个多行标量函数,这可能会非常慢。 3. 它想要达到什么目的?如果将其转换为 inline(即 inline)表值函数,您可能(将会?)获得更好的性能。
  • 这里的一个基本问题是,您如何使用它?如果您使用单个值调用它,则与将其应用于具有 1000 万行的查询完全不同。

标签: sql sql-server performance tsql


【解决方案1】:

标量函数很慢,内联函数很快。让我们从那个开始。您可以将标量 udf 重写为返回一行/一列的内联表值函数:

CREATE function [dbo].[fnEncClaimType_itvf](@in_ApptOrEncId numeric(8),@in_bool_IsApptId numeric(2)) 
returns table as return
(
    SELECT TOP 1 returnVal = CASE 
        WHEN BLH_PATINV_TEXT = 'AUTO' THEN 'Auto Accident' 
        WHEN BLH_PATINV_TEXT = 'EMPLOYER' THEN 'Employer' 
        WHEN BLH_PATINV_TEXT = 'PATCLM' THEN 'Self Pay' 
        WHEN BLH_PATINV_TEXT = 'PATINV' THEN 'Penalty Invoice' 
        WHEN BLH_PATINV_TEXT = 'PI' THEN 'Penalty Invoice' 
        WHEN BLH_PATINV_TEXT = 'INJURY' THEN 'Personal Accident' 
        WHEN BLH_PATINV_TEXT = 'PROF' THEN 'Professional' 
        WHEN BLH_PATINV_TEXT = 'TPA' THEN 'TPA' 
        WHEN BLH_PATINV_TEXT = 'UB04' THEN 'Institutional' 
        WHEN BLH_PATINV_TEXT = 'WORKCOMP' THEN 'Work Comp' 
        WHEN BLH_PATINV_TEXT = 'DMERC' THEN 'DMERC' ELSE '' 
        END 
    FROM TRN_BILLING_HEAD,TRN_ENCOUNTERS 
    WHERE @in_bool_IsApptId = 1
      AND BLH_ENC_ID = ENC_ID 
      AND (BLH_APPT_ID = @in_ApptOrEncId OR ENC_APPT_ID = @in_ApptOrEncId) 
      AND BLH_BOOL_INACTIVE = 0 
    ORDER BY BLH_ID
)
UNION ALL
    SELECT TOP 1 returnVal = CASE 
      WHEN BLH_PATINV_TEXT = 'AUTO' THEN 'Auto Accident'
      WHEN BLH_PATINV_TEXT = 'EMPLOYER' THEN 'Employer' 
      WHEN BLH_PATINV_TEXT = 'PATCLM' THEN 'Self Pay' 
      WHEN BLH_PATINV_TEXT = 'PATINV' THEN 'Penalty Invoice'
      WHEN BLH_PATINV_TEXT = 'PI' THEN 'Penalty Invoice' 
      WHEN BLH_PATINV_TEXT = 'INJURY' THEN 'Personal Accident' 
      WHEN BLH_PATINV_TEXT = 'PROF' THEN 'Professional' 
      WHEN BLH_PATINV_TEXT = 'TPA' THEN 'TPA' 
      WHEN BLH_PATINV_TEXT = 'UB04' THEN 'Institutional' 
      WHEN BLH_PATINV_TEXT = 'WORKCOMP' THEN 'Work Comp' 
      WHEN BLH_PATINV_TEXT = 'DMERC' THEN 'DMERC' ELSE '' END 
    FROM TRN_BILLING_HEAD 
    WHERE BLH_ENC_ID = @in_ApptOrEncId AND BLH_BOOL_INACTIVE = 0 
    ORDER BY BLH_ID
GO

这个:

SELECT dbo.fnEncClaimType(1,2);

变成:

SELECT returnValue FROM dbo.fnEncClaimType_itvf(1,2);

这个:

SELECT dbo.fnEncClaimType(1,2)
FROM   <some table>

变成:

SELECT      cl.returnValue 
FROM        <some table>
CROSS APPLY dbo.fnEncClaimType_itvf(1,2) AS cl;

【讨论】:

  • 另一种语法是SELECT (SELECT returnValue FROM dbo.fnEncClaimType_itvf(1,2)) FROM &lt;some table&gt;
猜你喜欢
  • 2011-02-07
  • 2012-04-18
  • 1970-01-01
  • 2018-02-07
  • 2013-08-04
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多