如何聚合行以降低SQL查询中的数据分辨率?

时间:2009-03-17 14:11:40

标签: sql-server reporting-services

我正在使用MSSQL 2000数据库,其中包含为环境中的所有服务器收集的大量Windows perfmon数据。我正在使用SSRS 2005构建自定义报告图表,以便随时间显示指标。

如果我想查看,比如上个月,大量的数据点会在X轴上创建一个丑陋的报告,标签不可读。我希望将数据汇总时间减少到 n 数据点,以便给出分组时间跨度的平均值。

我尝试使用花哨的GROUP BY子句构建查询,但是无法构建执行的东西。我认为这应该是SQL的常见任务,但我没有在网上找到任何答案。

表结构基本如下所示。这实际上是MOM 2005 OnePoint数据库,但我认为该应用程序无关紧要。

CREATE TABLE PerfTable (
   [time] datetime,
   value float,
   Server nvarchar(356),
   ObjectName nvarchar(225),
   CounterName nvarchar(225),
   InstanceName nvarchar(225),
   Scale float
);

5 个答案:

答案 0 :(得分:1)

可能值得构建一个View以查看数月的数据,并使用SQL背后的数据来减少数据量。

然后您可以从该视图运行报告。

此外,您可能需要了解所涉及的表格结构以及您目前用于获取结果的SQL。

答案 1 :(得分:0)

您真的需要减少从SQL返回的记录数量,还是只减少图表呈现的数据?

从SQL获取所有值可能更容易,然后将数据按到稍后更有用的东西上。更改查询将减少网络使用量,因为将发送更少的数据,但如果这不是一个问题,那么查询可能不是最好的地方。

答案 2 :(得分:0)

您可以使用DATEPART功能获取按特定日期,小时或分钟(或其他几个)过滤的数据块。您应该能够按这些分组并获得所需的平均值/总量。

好的,这是获得n个聚合的解决方案(就每个时间段的数据而言):

declare @points as int
declare @start as float
declare @period as float

set @points = 20

select 
@start=cast(min(time) as float), 
@period=cast(max(time)-min(time) as float) 
from perftable

select avg(value),
round((cast(time as float)-@start)/(@period/@points),0,1)
from perftable
group by
round((cast(time as float)-@start)/(@period/@points),0,1)

@points变量是您想要获得的数字od聚合。 @start是报告中浮动的第一条记录的时间 @period是报告中开始和结束日期之间的差异

其余几乎是将日期线性缩放到范围[0; @points],将结果截断为整数并按截断结果进行分组。

答案 3 :(得分:0)

假设我们希望在该范围内拥有3倍的时间和“平均值”。

首先我们确定期间..开始 - 结束,开始 - 结束,开始 - 结束等 这可以在你自己的代码中完成,所以我使用参数。

在此示例中,我们还按“服务器”进行分组,但您可以添加额外的列或将其删除。

DECLARE @startdate1 as DateTime
DECLARE @enddate1 as DateTime
DECLARE @startdate2 as DateTime
DECLARE @enddate2 as DateTime
DECLARE @startdate3 as DateTime
DECLARE @enddate3 as DateTime
SELECT 
  CASE WHEN time >= @startdate1 AND time < @enddate1 THEN 'PERIOD1'
    ELSE CASE WHEN time >= @startdate2 AND time < @enddate2 THEN 'PERIOD2'
     ELSE CASE WHEN time >= @startdate3 AND time < @enddate3 THEN 'PERIOD3' 
     END 
    END
  END as Period,
  AVG(p.[value]),
  p.[Server]
FROM PerfTable p
GROUP BY 
  CASE WHEN time >= @startdate1 AND time < @enddate1 THEN 'PERIOD1'
    ELSE CASE WHEN time >= @startdate2 AND time < @enddate2 THEN 'PERIOD2'
     ELSE CASE WHEN time >= @startdate3 AND time < @enddate3 THEN 'PERIOD3' 
     END 
    END
  END,
  p.[Server]

答案 4 :(得分:0)

我的解决方案与我的要求密切相关。如果我想按时间单位分组,那很简单:

按小时分组:

select
   dateadd(hh, datediff(hh, '1970-01-01', [time]), '1970-01-01'),
   Server, ObjectName, CounterName, InstanceName, avg(value)
from PerfTable
group by
   dateadd(hh, datediff(hh, '1970-01-01', [time]), '1970-01-01'),
   ComputerName, ObjectName, CounterName, InstanceName
order by
   dateadd(hh, datediff(hh, '1970-01-01', [time]), '1970-01-01') desc,
   ObjectName, CounterName, InstanceName, ComputerName

这并不能解决缩小到 n 数据点的需要。