这是我的问题,
我有一个观点叫另一个观点。第二个视图有一个标量函数,显然可以为表的每一行运行。仅限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
答案 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中进行计算。
除此之外,您在代码中使用了RIGHT
,LEFT
和SUBSTRING
函数。永远不要在WHERE
或JOIN
。尝试先计算它们并将它们转储到临时表中,以便计算一次。然后索引这些列上的临时表。
对于理论上的答案感到抱歉,但是现在代码似乎很乱。它需要经历多层变化才能获得不错的表现。
答案 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'