使用大型数据集计算机器在不同状态下花费的时间的有效方法
Efficient way of calculating time spent by machines in different states with a large dataset
我找不到解决这个问题的好方法。我有一个看起来像这样的数据集:
MACHINE DATETIME CODE
C54118PC1 2016-04-01 00:00:01.000 10
C54118PC1 2016-04-01 00:01:12.000 4
C54118PC1 2016-04-01 00:01:36.000 10
C54118PC1 2016-04-01 00:01:50.000 4
C54123PC1 2016-04-01 00:00:02.000 0
C54123PC1 2016-04-01 01:00:02.000 0
最终,我想在 Qlikview 文档中将其显示为饼图,显示机器在每个状态(代码)中花费的时间。
为了做到这一点,我想我需要以这种格式获取数据:
MACHINE DATE CODE DURATION
Machine1 07/06/2016 2 07:30:14
Machine1 07/06/2016 5 02:45:10
Machine2 07/06/2016 0 12:37:05
Machine2 07/06/2016 5 04:04:59
Machine1 08/06/2016 2 02:57:13
Machine1 08/06/2016 4 04:12:05
Machine1 08/06/2016 5 03:07:12
Machine3 08/06/2016 8 02:49:23
这将是每台机器每天每个代码的 1 行,以及当天和代码的总持续时间。
另一个考虑因素是这是一个大型数据集 - 目前至少有 200 万行,并且随着更多机器的添加和更多时间的流逝,这可能会增长得相当快。
所以,基本上我需要一种非常有效的方法来计算在不同状态(代码)下花费的时间,按机器和日期。我认为这最好在 SQL 中完成,但如果这样做效率更高,我也可以在 Qlikview 中完成。谁能帮忙?
提前致谢!
编辑:对不起,我忘了解释日志记录是如何工作的!我们有一堆机器在白天的各种状态(例如打印、空闲、清洁)之间交替。每次他们改变状态(例如从打印到空闲),他们记录一个时间戳和他们的新状态。
(他们还定期记录时间戳和当前状态,即使他们实际上并没有改变状态。)
持续时间计算为两个连续时间戳之间的时间差。
未经测试:
LEAD()
一个分析(window 函数)让您可以查看给定数据分区的下一个有序行值似乎可行...
所以在这种情况下:我们想要给定机器的下一行的日期时间,而不管状态如何......类似于:
SELECT MACHINE
, FORMAT(DATETIME, 'DD/MM/YYYY')
, CODE
, SUM(Lead(DateTIme) over (partition by Machine order by dateTime asc) - datetime) AS DURATION,
FROM TABLENAME
GROUP BY MACHINE, CODE, FORMAT(DATETIME, 'DD/MM/YYYY')
我不确定这里的数据数学如何计算持续时间。
试试这个
Declare @Table table (machine varchar(25),DateTime datetime,Code int)
Insert into @Table (Machine,DateTime,Code) values
('Machine1','2016-04-01 00:00:01.000',10),
('Machine1','2016-04-01 00:01:12.000',4),
('Machine1','2016-04-01 00:01:36.000',10),
('Machine1','2016-04-01 00:01:50.000',4),
('Machine2','2016-04-01 00:00:02.000',0),
('Machine2','2016-04-01 01:00:02.000',0),
('Machine1','2016-04-02 00:00:01.000',10),
('Machine1','2016-04-02 00:01:12.000',4),
('Machine1','2016-04-02 00:01:36.000',10),
('Machine1','2016-04-02 00:01:50.000',4),
('Machine2','2016-04-02 00:00:02.000',0),
('Machine2','2016-04-02 01:00:02.000',0)
IF OBJECT_ID('tempdb.dbo.#Temp1', 'U') IS NOT NULL
DROP TABLE #Temp1;
-- Generate Date Range
Select Distinct DateR1=cast(DateTime as Date),DateR2=DateAdd(DD,1,cast(DateTime as Date)) into #Temp1 from @Table
Create Index idx on #Temp1 (DateR1,DateR2)
;with cteBase as (
Select *
,MSDate1 = DateTime
,MSDate2 = Lead(DateTime,1,DateAdd(DD,1,cast(DateTime as Date))) over (Partition by Machine Order by Machine,DateTime)
From @Table
)
Select Machine
,Date = DateR1
,Code
,Duration = CONVERT(varchar, DATEADD(SS, sum(DateDiff(SS,case when MSDate1<=DateR1 then DateR1 else MSDate1 end,case when MSDate2>DateR2 then DateR2 else MSDate2 end)), 0), 114)
From #Temp1 A
Join cteBase B on (MSDate1 between DateR1 and DateR2 or MSDate2 between DateR1 and DateR2)
Group By Machine
,DateR1
,Code
Returns
Machine Date Code Duration
Machine1 2016-04-01 4 23:58:34:000
Machine1 2016-04-01 10 00:01:25:000
Machine1 2016-04-02 4 23:58:35:000
Machine1 2016-04-02 10 00:01:25:000
Machine2 2016-04-01 0 23:59:58:000
Machine2 2016-04-02 0 00:00:00:000
这可以在 QV 本身中轻松实现(参见下面的脚本)。
关于数据大小。您可以在 QV 中实现 Incremental Load
并在重新加载应用程序时仅加载新记录,并且仅对小集执行转换而不是对完整数据集执行转换。
示例工作流将是:在每次重新加载时仅提取最后日期的记录,执行转换,从 qvd 加载先前转换的数据并将新结果连接到 qvd。这是 QV 非常常见的方法(我每天都在使用它)。通常我更喜欢这种方法,因为我不会推动数据库来完成 QV 的工作并避免与 DBA 发生冲突;)
如果你愿意,我可以粘贴带有增量加载的示例脚本(只需留下评论)
有关增量加载的更多详细信息:
- http://www.quickintelligence.co.uk/qlikview-incremental-load/
- http://www.analyticsvidhya.com/blog/2014/09/qlikview-incremental-load/
示例脚本:
RawData:
Load
MACHINE,
// DATETIME, // this is not needed anymore
CODE,
date(left(DATETIME, 10)) as Date, // extract the date
mid(DATETIME, 12, 8) as Duration // extract the duration
;
Load * Inline [
MACHINE , DATETIME , CODE
C54118PC1 , 2016-04-01 00:00:01.000 , 10
C54118PC1 , 2016-04-01 00:01:12.000 , 4
C54118PC1 , 2016-04-01 00:01:36.000 , 10
C54118PC1 , 2016-04-01 00:01:50.000 , 4
C54123PC1 , 2016-04-01 00:00:02.000 , 0
C54123PC1 , 2016-04-01 01:00:02.000 , 0
];
Data:
Load
interval(sum(Duration)) as TotalDuration, // sum the total duration and convert it to timestamp format
MACHINE,
Date,
CODE
Resident
RawData
Group By
MACHINE,
Date,
CODE
;
Drop Table RawData; // this table is not needed anymore
我找不到解决这个问题的好方法。我有一个看起来像这样的数据集:
MACHINE DATETIME CODE C54118PC1 2016-04-01 00:00:01.000 10 C54118PC1 2016-04-01 00:01:12.000 4 C54118PC1 2016-04-01 00:01:36.000 10 C54118PC1 2016-04-01 00:01:50.000 4 C54123PC1 2016-04-01 00:00:02.000 0 C54123PC1 2016-04-01 01:00:02.000 0
最终,我想在 Qlikview 文档中将其显示为饼图,显示机器在每个状态(代码)中花费的时间。
为了做到这一点,我想我需要以这种格式获取数据:
MACHINE DATE CODE DURATION Machine1 07/06/2016 2 07:30:14 Machine1 07/06/2016 5 02:45:10 Machine2 07/06/2016 0 12:37:05 Machine2 07/06/2016 5 04:04:59 Machine1 08/06/2016 2 02:57:13 Machine1 08/06/2016 4 04:12:05 Machine1 08/06/2016 5 03:07:12 Machine3 08/06/2016 8 02:49:23
这将是每台机器每天每个代码的 1 行,以及当天和代码的总持续时间。
另一个考虑因素是这是一个大型数据集 - 目前至少有 200 万行,并且随着更多机器的添加和更多时间的流逝,这可能会增长得相当快。
所以,基本上我需要一种非常有效的方法来计算在不同状态(代码)下花费的时间,按机器和日期。我认为这最好在 SQL 中完成,但如果这样做效率更高,我也可以在 Qlikview 中完成。谁能帮忙?
提前致谢!
编辑:对不起,我忘了解释日志记录是如何工作的!我们有一堆机器在白天的各种状态(例如打印、空闲、清洁)之间交替。每次他们改变状态(例如从打印到空闲),他们记录一个时间戳和他们的新状态。
(他们还定期记录时间戳和当前状态,即使他们实际上并没有改变状态。)
持续时间计算为两个连续时间戳之间的时间差。
未经测试:
LEAD()
一个分析(window 函数)让您可以查看给定数据分区的下一个有序行值似乎可行...
所以在这种情况下:我们想要给定机器的下一行的日期时间,而不管状态如何......类似于:
SELECT MACHINE
, FORMAT(DATETIME, 'DD/MM/YYYY')
, CODE
, SUM(Lead(DateTIme) over (partition by Machine order by dateTime asc) - datetime) AS DURATION,
FROM TABLENAME
GROUP BY MACHINE, CODE, FORMAT(DATETIME, 'DD/MM/YYYY')
我不确定这里的数据数学如何计算持续时间。
试试这个
Declare @Table table (machine varchar(25),DateTime datetime,Code int)
Insert into @Table (Machine,DateTime,Code) values
('Machine1','2016-04-01 00:00:01.000',10),
('Machine1','2016-04-01 00:01:12.000',4),
('Machine1','2016-04-01 00:01:36.000',10),
('Machine1','2016-04-01 00:01:50.000',4),
('Machine2','2016-04-01 00:00:02.000',0),
('Machine2','2016-04-01 01:00:02.000',0),
('Machine1','2016-04-02 00:00:01.000',10),
('Machine1','2016-04-02 00:01:12.000',4),
('Machine1','2016-04-02 00:01:36.000',10),
('Machine1','2016-04-02 00:01:50.000',4),
('Machine2','2016-04-02 00:00:02.000',0),
('Machine2','2016-04-02 01:00:02.000',0)
IF OBJECT_ID('tempdb.dbo.#Temp1', 'U') IS NOT NULL
DROP TABLE #Temp1;
-- Generate Date Range
Select Distinct DateR1=cast(DateTime as Date),DateR2=DateAdd(DD,1,cast(DateTime as Date)) into #Temp1 from @Table
Create Index idx on #Temp1 (DateR1,DateR2)
;with cteBase as (
Select *
,MSDate1 = DateTime
,MSDate2 = Lead(DateTime,1,DateAdd(DD,1,cast(DateTime as Date))) over (Partition by Machine Order by Machine,DateTime)
From @Table
)
Select Machine
,Date = DateR1
,Code
,Duration = CONVERT(varchar, DATEADD(SS, sum(DateDiff(SS,case when MSDate1<=DateR1 then DateR1 else MSDate1 end,case when MSDate2>DateR2 then DateR2 else MSDate2 end)), 0), 114)
From #Temp1 A
Join cteBase B on (MSDate1 between DateR1 and DateR2 or MSDate2 between DateR1 and DateR2)
Group By Machine
,DateR1
,Code
Returns
Machine Date Code Duration
Machine1 2016-04-01 4 23:58:34:000
Machine1 2016-04-01 10 00:01:25:000
Machine1 2016-04-02 4 23:58:35:000
Machine1 2016-04-02 10 00:01:25:000
Machine2 2016-04-01 0 23:59:58:000
Machine2 2016-04-02 0 00:00:00:000
这可以在 QV 本身中轻松实现(参见下面的脚本)。
关于数据大小。您可以在 QV 中实现 Incremental Load
并在重新加载应用程序时仅加载新记录,并且仅对小集执行转换而不是对完整数据集执行转换。
示例工作流将是:在每次重新加载时仅提取最后日期的记录,执行转换,从 qvd 加载先前转换的数据并将新结果连接到 qvd。这是 QV 非常常见的方法(我每天都在使用它)。通常我更喜欢这种方法,因为我不会推动数据库来完成 QV 的工作并避免与 DBA 发生冲突;)
如果你愿意,我可以粘贴带有增量加载的示例脚本(只需留下评论)
有关增量加载的更多详细信息:
- http://www.quickintelligence.co.uk/qlikview-incremental-load/
- http://www.analyticsvidhya.com/blog/2014/09/qlikview-incremental-load/
示例脚本:
RawData:
Load
MACHINE,
// DATETIME, // this is not needed anymore
CODE,
date(left(DATETIME, 10)) as Date, // extract the date
mid(DATETIME, 12, 8) as Duration // extract the duration
;
Load * Inline [
MACHINE , DATETIME , CODE
C54118PC1 , 2016-04-01 00:00:01.000 , 10
C54118PC1 , 2016-04-01 00:01:12.000 , 4
C54118PC1 , 2016-04-01 00:01:36.000 , 10
C54118PC1 , 2016-04-01 00:01:50.000 , 4
C54123PC1 , 2016-04-01 00:00:02.000 , 0
C54123PC1 , 2016-04-01 01:00:02.000 , 0
];
Data:
Load
interval(sum(Duration)) as TotalDuration, // sum the total duration and convert it to timestamp format
MACHINE,
Date,
CODE
Resident
RawData
Group By
MACHINE,
Date,
CODE
;
Drop Table RawData; // this table is not needed anymore