背景
我有一个存储过程,它返回大量的用电量测量数据。每条记录由测量的日期和时间以及四个测量值组成。执行测量的速率从几秒到几分钟不等,在我的示例中(以及在我的真实数据中),间隔为 15 分钟,但可能会更低。
由于数据的存储方式(所有测量的值都被压缩并以原始格式存储在单列中),我正在使用的存储过程正在调用一个处理数据并返回结果集的外部程序集。
例子
EXEC dbo.sp_get_energy_consumption @Identify, @StartTime, @EndTime, @Args
现在存储过程需要一些参数。@Identify
是int
并且表示测量设备的标识符。@Args
是nvarchar
并指示四个测量值中的哪一个将包含在结果集中。两者@StartTime
和@EndTime
都非常简单,它们datetime
用于限制记录的范围。
存储过程本身定义为:
CREATE PROCEDURE sp_get_energy_consumption
@identify int,
@startTime datetime,
@endTime datetime,
@args nvarchar(60)
AS
EXTERNAL NAME Procedury.StoredProcedures.akd_energy_consumption_list
执行时,根据参数,结果可能如下所示。
EXEC dbo.sp_get_energy_consumption 1, N'2013-01-08 00:00:00', N'2013-01-09 00:00:00', N'i,e'
ID | Time | V1 | V2 | V3 | V4 |
1 | 2013-01-08 15:30:00 | 111.42 | 0.24 | NULL | NULL |
2 | 2013-01-08 15:45:00 | 111.90 | 0.24 | NULL | NULL |
3 | 2013-01-08 16:00:00 | 112.34 | 0.24 | NULL | NULL |
4 | 2013-01-08 16:15:00 | 112.96 | 0.24 | NULL | NULL |
...
问题
我即将开发的 Web 应用程序应该以表示选定日期范围的图表的形式将这些数据可视化。我还必须根据日期范围和图表比例按小时、天、周或月对记录进行分组,因为将大约 3,000 条记录传输给客户只是为了呈现一些小的一个月图表是行不通的。例如,我必须削减数字并计算每月或每周每一天的一些最小值、最大值、平均值和标准偏差。
我是 SQL Server 的新手,所以我搜索了一下,发现了一种将存储过程转换为表值函数的可能方法,因此编写了一个非常简单的 TVF,它基本上只是调用存储过程并返回一个我可以用来执行另一个SELECT
s 的表,但我失败了,因为 SQL Server 不允许我INSERT EXEC
进入 TVF 结果表。
CREATE FUNCTION dbo.fn_get_energy_consumption(@Identify int, @StartTime datetime, @EndTime datetime, @Args nvarchar(30))
RETURNS @ConsumptionList TABLE
(
Id INT IDENTITY,
Time DATETIME,
V1 FLOAT NULL,
V2 FLOAT NULL,
V3 FLOAT NULL,
V4 FLOAT NULL
)
AS
BEGIN
INSERT @ConsumptionList
EXEC dbo.sp_get_energy_consumption @Identify, @StartTime, @EndTime, @Args
RETURN
END
GO
错误:
消息 443,级别 16,状态 14,过程 fn_get_energy_consumption,第 16 行
在函数中无效使用副作用运算符“INSERT EXEC”。
我还没有尝试过的另一种可能性是使用OPENROWSET
which 这是我想避免的东西,如果可能的话。
我也有点担心整体性能,因为在我使用 3 年的四核工作站上,执行存储过程调用大约需要 5 分钟,返回大约 6,800 条记录(几乎 2.5 个月)以及所有四个测量值(需要一半只选择了两个的时间),如果不将它缓存在某个表或其他东西中,我无能为力。
但是现在我很乐意弄清楚如何从存储过程中获取一个表。
更新 1
由于存储过程的性能不佳,我正在考虑编写执行长时间运行的 CLR 存储过程 ( sp_get_energy_consumption
) 的周期性任务并将结果保存到用作缓存的常规表中。这样,我将通过使用表值函数来实现我所获得的结果,而表值函数的执行时间要短得多,以便以后查询。
就目前而言,我想到的唯一缺点是放弃对实时数据的访问,因为定期任务执行之间的间隔总会产生一些延迟。