我的SQL Server表运行特别慢,我不知道为什么。该表有7列,其中5列是函数标量,它们全部计算特定日期另一张表中相似数据的每日平均值。前两列只是每天的时间戳,以及正在创建数据的特定项目的itemId。
前两列都是主键,这些函数是确定性的,但由于该函数使用用户数据而无法保留,我怀疑是因为我从函数中的原始数据表中进行选择,但是我不确定。
如果将某列的类型设置为平均函数,则最终需要5秒钟来计算20个条目。这对于我们的应用程序来说太慢了,并且会导致错误。做这个的最好方式是什么?如果当前设置是最好的,如何减少造成的延迟?我主要是想避免像同事们希望的那样对数据进行硬编码,因为我需要找出一种方法,使SQL表每天自动填充,并为添加到原始数据表中的每个新ItemId
自动填充
谢谢!
我已经尝试过使函数具有确定性,用户数据使我无法使其保持不变,我认为这可能会提高速度,因为平均数通常不需要在完成后就更改。
这是在运行SQL Server 2017的Microsoft Windows Server上
CREATE TABLE [dbo].[DCP_AvgData]
(
[AssetID] [NVARCHAR](255) NOT NULL,
[Time_Stamp] [DATETIME2](7) NOT NULL,
[DeviceFlowYesterday] AS ([dbo].[AVERG]([Time_Stamp], [AssetID])),
CONSTRAINT [PK_DCP_AvgData]
PRIMARY KEY CLUSTERED ([Time_Stamp] ASC, [AssetID] ASC)
WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
GO
ALTER FUNCTION [dbo].[AVERG]
(--@floatVal FLOAT,
@Time_Stamp DATETIME2(7),
@AssetID NVARCHAR(255))
RETURNS FLOAT
WITH SCHEMABINDING
AS
BEGIN
-- Declare the return variable here
DECLARE @ResultVar FLOAT
DECLARE @result FLOAT
DECLARE @time DATETIME2(7)
SET @result = (SELECT MAX(Pump1Yesterday)
FROM dbo.DCP_FloatData
WHERE @AssetID = AssetID
AND CONVERT(DATETIME2(7), Time_Stamp, 121) >= CONVERT(DATETIME2(7), DATEADD(dd, 0, DATEDIFF(dd, 0, @Time_Stamp)), 121)
AND CONVERT(DATETIME2(7), Time_Stamp, 121) <= CONVERT(DATETIME2(7), @Time_Stamp, 121)
AND Pump1Yesterday>5);
-- Return the result of the function
RETURN @ResultVar
END
当我有20行时,查询需要大约5秒钟的时间来加载,这太可怕了,因为我需要数百行,并且最多只能有1秒的时间
答案 0 :(得分:0)
根据上面指定的数据类型,CONVERT
语句可以完全删除。另外,由于Time_Stamp
比较看起来是“它必须与@Time_Stamp
值在同一天,并且一天中不得早于该值”,因此整个查询可以这样重写: / p>
ALTER FUNCTION [dbo].[AVERG]
(
--@floatVal FLOAT,
@Time_Stamp Datetime2(7),
@AssetID nvarchar(255)
)
RETURNS FLOAT
WITH SCHEMABINDING
AS
BEGIN
-- Declare the return variable here
DECLARE @ResultVar FLOAT
SET @ResultVar=( SELECT MAX(Pump1Yesterday) FROM dbo.DCP_FloatData
where @AssetID=AssetID
AND Time_Stamp >= CAST(@Time_Stamp as Date)
AND Time_Stamp <= @Time_Stamp
AND Pump1Yesterday>5);
-- Return the result of the function
RETURN @ResultVar
END
您还应该在数据源表(DCP_FloatData
)上有一个索引,知道该表中Time_Stamp字段的数据类型将很有帮助。我假设此代码为DATETIME2(7)
。
最后,您的数据源应具有索引。根据上面的代码,这两个索引之一应该是最佳的:
CREATE INDEX Idx_DCP_FloatData_AssetId_Time_Stamp_Include
ON DCP_FloatData (AssetId, Time_Stamp) INCLUDE (Pump1Yesterday)
-- OR
CREATE INDEX Idx_DCP_DCP_FloatData_AssetId_Time_Stamp_Pump1Yesterday
ON DCP_FloatData (AssetId, Time_Stamp, Pump1Yesterday)
哪种最佳选择取决于您的数据分布,值和行数,我从这里无法得知。