优化sql server标量值函数

时间:2015-02-25 14:52:35

标签: sql-server function

这是我的问题,

我有一个观点叫另一个观点。第二个视图有一个标量函数,显然可以为表的每一行运行。仅限322行,大约需要30秒。当我取出计算字段时,需要1秒钟。

如果我们能够优化功能,或者是否有其他方法可以提高性能,我感谢你们。

这是功能:

ALTER FUNCTION [dbo].[fnCabinetLoad] (
@site    nvarchar(15),
@cabrow  nvarchar(50),
@cabinet nvarchar(50))

RETURNS float
AS BEGIN
    -- Declare the return variable here
    DECLARE @ResultVar float

    -- Add the T-SQL statements to compute the return value here
    SELECT @ResultVar = SUM(d.Value)
    FROM 
    (
      SELECT dt.*, 
      ROW_NUMBER() 
          OVER (PARTITION BY dt.tagname ORDER BY  dt.timestamp DESC) 'RowNum'
      FROM vDataLog dt
     WHERE dt.Timestamp BETWEEN dateadd(minute,-15,getdate()) AND GetDate()
    ) d 
    INNER JOIN [SKY_EGX_CONFIG].[dbo].[vPanelSchedule] AS p
        ON p.rpp = left(d.TagName,3) + substring(d.TagName,5,5) 
             + substring(d.TagName,11,8)
       AND right(p.pole,2) = substring(d.TagName,23,2)
       AND p.site = @site
       AND p.EqpRowNumber  = @cabrow
       AND p.EqpCabinetName= @cabinet
    WHERE d.RowNum = 1
    AND Right(d.TagName, 6) = 'kW Avg'

RETURN @ResultVar

END

4 个答案:

答案 0 :(得分:1)

标量值函数具有恶劣的性能。您的函数看起来像是CROSS APPLY

的内联表值函数的绝佳候选者
CREATE FUNCTION [dbo].[fnCabinetLoad]
(
@site    nvarchar(15),
@cabrow  nvarchar(50),
@cabinet nvarchar(50)
)
RETURNS TABLE
AS RETURN
    SELECT SUM(d.Value) AS [TotalLoad]
    FROM 
    (
      SELECT dt.*, ROW_NUMBER() OVER (PARTITION BY dt.tagname ORDER BY  dt.timestamp DESC) 'RowNum'
      FROM vDataLog dt
     WHERE dt.Timestamp BETWEEN dateadd(minute,-15,getdate()) AND GetDate()) d INNER JOIN [SKY_EGX_CONFIG].[dbo].[vPanelSchedule] AS p
    ON p.rpp           = left(d.TagName,3) + substring(d.TagName,5,5) + substring(d.TagName,11,8)
   AND right(p.pole,2) = substring(d.TagName,23,2)
   AND p.site = @site
   AND p.EqpRowNumber  = @cabrow
   AND p.EqpCabinetName= @cabinet
 WHERE d.RowNum = 1
   AND Right(d.TagName, 6) = 'kW Avg'

在您看来:

SELECT ..., cabinetLoad.TotalLoad
FROM ... CROSS APPLY dbo.fnCabinetLoad(.., .., ..) AS cabinetLoad

答案 1 :(得分:0)

我的理解是返回的结果集是322行,但是如果vDataLog表明显更大,我将首先运行该子查询并将该结果集转储到表变量中。然后,您可以使用该表变量而不是嵌套查询。

否则,就像现在一样,我认为连接是在嵌套查询的所有行上完成的,然后你用where子句剥离它们以获得你想要的行。

答案 2 :(得分:0)

你真的不需要一个功能并摆脱嵌套视图(性能非常差)!将整个逻辑封装在存储过程中以获得所需的结果,以便不是逐行计算所有内容,而是将其计算为集合。而不是查看,使用源表在存储的proc中进行计算。

除此之外,您在代码中使用了RIGHTLEFTSUBSTRING函数。永远不要在WHEREJOIN。尝试先计算它们并将它们转储到临时表中,以便计算一次。然后索引这些列上的临时表。

对于理论上的答案感到抱歉,但是现在代码似乎很乱。它需要经历多层变化才能获得不错的表现。

答案 3 :(得分:0)

将功能转换为视图。

通过限制列站点,cabrow和cabinet以及Timestamp来使用它。这样做时,尝试在变量上存储GetDate()和dateadd(分钟,-15,getdate())。我认为不这样做可能会阻止您利用Timestamp上的任何索引。

SELECT SUM(d.Value) AS [TotalLoad],
       dt.Timestamp,
       p.site,
       p.EqpRowNumber AS cabrow,
       p.EqpCabinetName AS cabinet
FROM 
( SELECT dt.*, 
  ROW_NUMBER() OVER (PARTITION BY dt.tagname ORDER BY dt.timestamp DESC)'RowNum'
  FROM vDataLog dt) d 
INNER JOIN [SKY_EGX_CONFIG].[dbo].[vPanelSchedule] AS p
ON p.rpp = left(d.TagName,3) + substring(d.TagName,5,5) + substring(d.TagName,11,8)
AND right(p.pole,2) = substring(d.TagName,23,2)
WHERE d.RowNum = 1
AND d.TagName LIKE '%kW Avg'