SQL Server:关于存储过程结果的统计函数?
Posted
技术标签:
【中文标题】SQL Server:关于存储过程结果的统计函数?【英文标题】:SQL Server : statistical functions on stored procedure result? 【发布时间】:2013-08-04 12:40:36 【问题描述】:背景
我有一个存储过程,它返回大量的用电量测量数据。每条记录由测量的日期和时间以及四个测量值组成。执行测量的速率从几秒到几分钟不等,在我的示例中(以及在我的真实数据中),间隔是 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 |
...
问题
我即将开发的网络应用程序应该以图表的形式将这些数据可视化,代表选定的日期范围。我还必须根据日期范围和图表比例按小时、天、周或月对记录进行分组,因为将大约 3,000 条记录传输给客户只是为了呈现一些小的一个月图表是行不通的。例如,我必须削减数字并计算每月或每周每一天的一些最小值、最大值、平均值和标准差。
我是 SQL Server 的新手,所以我用 Google 搜索了一下,发现了一种将存储过程转换为表值函数的可能方法,因此编写了一个非常简单的 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
,如果可能的话,我想避免。
我也有点担心整体性能,因为在我使用 3 年的四核工作站上,执行存储过程调用大约需要 5 分钟,返回大约 6,800 条记录(几乎 2.5 个月)以及所有四个测量值(只选择两个需要一半的时间),如果不将其缓存在某个表或其他东西中,我无能为力。
但现在我很乐意弄清楚如何从存储过程中获取表。
更新 1
由于存储过程的性能不佳,我正在考虑编写执行长时间运行的 CLR 存储过程 (sp_get_energy_consumption
) 的周期性任务并将结果保存到用作缓存的常规表中。通过这种方式,我将通过使用表值函数来实现我将获得的结果,并且以后查询的执行时间要短得多。
就目前而言,我想到的唯一缺点是放弃对实时数据的访问,因为定期任务执行之间的间隔总会产生一些延迟。
【问题讨论】:
你对数据库有写权限吗? 只要我在我的测试环境中,我还没有真正的生产环境可供我访问。我只提供了真实数据,它带有完整的数据库结构。dbo.sp_get_energy_consumption
只是外部 CLR 存储过程的名称。
您不应将存储过程命名为 sp_anything
: msdn.microsoft.com/en-us/library/dd172115(v=vs.100).aspx
【参考方案1】:
因为我没有你的数据或统计SP,所以这个语法有点不对劲。 虽然我的本能是使用表变量;显然那些是明确不允许的。相反,我使用的是临时表。
ALTER PROCEDURE [dbo].[STEVETEST]
-- Add the parameters for the stored procedure here
@Identify INT,
@StartTime DATETIME,
@EndTime Datetime,
@args nvarchar(30)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
CREATE TABLE #tbl (ID INT IDENTITY, IDEN INT, TIME1 DATETIME, V1 FLOAT NULL, V2 FLOAT NULL, V3 FLOAT NULL, V4 FLOAT NULL)
INSERT INTO #tbl EXEC SP_STATITISTICS_PACKAGE
SELECT * FROM #tbl
DROP TABLE #tbl
在上面的示例中,我没有将任何参数传递给“SP_STATISTICS_PACKAGE”,但这只是我的懒惰。 重点是演示通过嵌套存储过程填充临时表的语法。我明确删除了我的临时表,但是只要连接关闭,它就应该删除。如果您在同一连接上多次运行此 USP 而未明确删除它,您将收到表存在错误。 另外,我建议使用比 #tbl 更独特的临时表名称。
【讨论】:
所以基本上,您建议编写一个存储过程,在其中我调用加载数据的外部存储过程,将它们插入到临时表中,然后对所有需要的统计数据执行 SELECT,对吗? 总结一下。如果你愿意,你也可以在主存储过程中做所有的统计工作。不是前端的人,我不知道哪个更可取。【参考方案2】:以下是一些需要考虑的方法:
(1) 使用返回表的存储过程,但始终将其称为:
insert into xxx
exec(. . .)
然后您可以重复使用该表,一次用于显示给用户,一次用于计算统计数据。
(2) 有一个规范表,存储过程运行时将填充该表。所以存储过程本质上变成了:
truncate table xxx
do work
insert into xxx(...)
<whatever should go here>
这适用于您不必担心两个用户相互干扰的单用户系统。
(3) 传入一个表名并将其填充到存储过程中。但是,只有在您的应用程序已经广泛使用动态 SQL 时,您才应该这样做。在大多数情况下,强烈建议不要这样做。
(4)(2 的变体)维护所有运行的历史记录。在表中包含一个 runid 并传回该 runid。然后代码看起来像:
insert into runHistory(@RunId, . . .)
select @RunId, . . .
存储过程返回@RunId,然后由应用程序使用。使用适当的索引,表的大小对性能的影响应该很小。此外,您还可以保留历史记录。
(5) 可能是更推荐的方法。看起来您每天都会创建一个汇总表。每天运行存储过程以汇总最新数据并将其添加到汇总表中。这假设您不需要最新信息,因此可以接受一天的延迟。
【讨论】:
以上是关于SQL Server:关于存储过程结果的统计函数?的主要内容,如果未能解决你的问题,请参考以下文章