每行执行多个标量函数的最有效方法

rei*_*ito 3 sql t-sql sql-server-2008

我正在努力加快我的查询速度.我需要每行运行2个标量值函数,并将几列作为参数.

这些函数基于运行总计进行计算,并且没有简单的方法(我知道)在SQL Server 2008中执行此操作.

我的查询的CTE部分获取了我需要计算的所有行,并且需要为每个级别单独运行.客户与商店之间的关系是一对多,但您无法根据其每个商店计算在客户端级别(Store ='All')进行计算.

我的第一次尝试是在'SELECT'语句中调用函数,但我读到它们将同步运行,这是不必要的.下面的尝试试图将计算转换为表值,以尝试异步运行它们.

我想知道OUTER APPLY是否可行,或者是否有更有效的方法来解决这个问题.

如果需要更多信息,请告诉我!

DECLARE @StartTime INT
SET @StartTime=20170101

DECLARE @EndTime INT
SET @EndTime=20170131


;WITH IsAvgStores AS (
    SELECT
        COALESCE(ParentClient,'All') AS ParentClient,
        COALESCE(Client,'All') AS Client,
        COALESCE(Store,'All') AS Store,
        MAX(Answer_Threshold),
        MAX(SL_Threshold)
    FROM 
        client_hierarchy
    WHERE 
        GETDATE() BETWEEN EFF_BEGIN_DATE AND EFF_END_DATE 
    GROUP BY ROLLUP(ParentClient,Client,Store)
)
SELECT I.ParentClient,I.Client,I.Store
    ,SL.isAvg_SL_String
    ,A.isAvg_ASA_String
INTO #isAvgTemp
FROM IsAvgStores I
    OUTER APPLY ( SELECT dbo.isAvg_S_B(ParentClient,Client,Store,Answer_Threshold,@StartTime,@EndTime) AS isAvg_SL_String 
                ) SL
    OUTER APPLY ( SELECT dbo.isAvg_A_B(ParentClient,Client,Store,SL_Threshold,@StartTime,@EndTime)     AS isAvg_ASA_String
                ) A
WHERE ParentClient<>'All'

SELECT * 
FROM #isAvgTemp
Run Code Online (Sandbox Code Playgroud)

Gor*_*off 5

这个评论太长了.

outer apply对于标量值函数来说,这是多余的.你可以这样做:

SELECT I.ParentClient, I.Client, I.Store,
      dbo.isAvg_S_B(ParentClient, Client, Store,A nswer_Threshold, @StartTime, @EndTime) AS isAvg_SL_String,
      dbo.isAvg_A_B(ParentClient, Client, Store, SL_Threshold, @StartTime, @EndTime) as isAvg_ASA_String
INTO #isAvgTemp
FROM IsAvgStores I
WHERE ParentClient <> 'All';
Run Code Online (Sandbox Code Playgroud)

这对性能完全没有影响; 它只是简化了查询.

为了提高性能,您有三种选择:

  • 重写代码以删除函数; 使用outer apply的运行总和.
  • 重写代码以删除函数; 使用递归CTE来计算运行总和.
  • 重写代码以删除函数; 使用游标来计算运行总和.

这些都不是最佳的.如果个别群体很小,前两个可能会有效.第三种可能是这种情况下的最佳选择 - 请注意我非常厌恶游标.

或者,您最好的选择:升级到更高版本的SQL Server并使用SQL Server 2012+中提供的累积和函数.