我有一个包含多个不同类型的时间序列的表。来自不同系列的内聚点的时间戳不完全匹配(即差异可能长达一个小时)。
下面是带有两个示例系列的架构:
CREATE TABLE series (id integer, series_type integer, charttime timestamp,
value integer, PRIMARY KEY (id));
INSERT INTO series VALUES (1, 1, '2018-03-01 12:10:00', 40),
(2, 1, '2018-03-01 13:25:00', 30), (3, 1, '2018-03-01 14:10:00', 50);
INSERT INTO series VALUES (4, 2, '2018-03-01 11:20:00', 2), (5, 2, '2018-03-01 12:15:00', 6),
(6, 2, '2018-03-01 13:00:00', 7), (7, 2, '2018-03-01 13:45:00', 1);
id |series_type |charttime |value |
---|------------|--------------------|------|
1 |1 |2018-03-01 12:10:00 |40 |
2 |1 |2018-03-01 13:25:00 |30 |
3 |1 |2018-03-01 14:10:00 |50 |
4 |2 |2018-03-01 11:20:00 |2 |
5 |2 |2018-03-01 12:15:00 |6 |
7 |2 |2018-03-01 13:45:00 |1 |
6 |2 |2018-03-01 13:00:00 |7 |
Run Code Online (Sandbox Code Playgroud)
目标是从另一个系列中选择一个系列以及最近的数据点。对于示例数据集,结果应该是:
charttime |s1 |s2 |
--------------------|---|---|
2018-03-01 12:10:00 |40 |6 |
2018-03-01 13:25:00 |30 |1 |
2018-03-01 14:10:00 |50 |1 |
Run Code Online (Sandbox Code Playgroud)
我目前的方法是通过子查询从其他系列中选择最匹配的数据点:
SELECT l.charttime, l.value AS s1,
( SELECT r.value
FROM series r
WHERE ABS( EXTRACT( EPOCH FROM l.charttime - r.charttime ) / 3600 ) < 1
AND r.series_type = 2
ORDER BY ABS( EXTRACT( EPOCH FROM l.charttime - r.charttime )) ASC LIMIT 1
) AS s2
FROM series l
WHERE l.series_type = 1
ORDER BY l.charttime ASC
Run Code Online (Sandbox Code Playgroud)
这似乎不是最好的方法,因为数据集非常庞大,因此执行许多子查询会减慢查询速度。
一个不同的想法是自连接表并过滤关闭数据时间戳:
SELECT l.charttime, l.value AS s1, r.charttime, r.value AS s2
FROM series l, series r
WHERE abs(EXTRACT(EPOCH FROM l.charttime - r.charttime) / 3600) < 1
AND l.series_type = 1 AND r.series_type = 2
charttime |s1 |charttime |s2 |
--------------------|---|--------------------|---|
2018-03-01 12:10:00 |40 |2018-03-01 11:20:00 |2 |
2018-03-01 12:10:00 |40 |2018-03-01 12:15:00 |6 |
2018-03-01 12:10:00 |40 |2018-03-01 13:00:00 |7 |
2018-03-01 13:25:00 |30 |2018-03-01 13:45:00 |1 |
2018-03-01 13:25:00 |30 |2018-03-01 13:00:00 |7 |
2018-03-01 14:10:00 |50 |2018-03-01 13:45:00 |1 |
Run Code Online (Sandbox Code Playgroud)
那么问题是重复的数据点。第一列中的分组不起作用,因为s2
无法选择最佳匹配。
有没有更好的方法?
在第二种方法中,通过自连接,您可以使用删除重复项row_number()
,
按 l.charttime 分区,按时间差排序并过滤 row_number = 1。
然而,我认为性能会很糟糕。由于笛卡尔连接,这将是一个 O(size(series 1) x size(series 2)) 操作。
在函数内部同时使用 l.charttime 和 r.charttime 也可能会造成麻烦。尝试重构(以伪代码)
r.charttime < l.charttime + 3600
and r.charttime > l.charttime - 3600
Run Code Online (Sandbox Code Playgroud)
..并查看查询计划的外观。我猜想图表时间上有一个索引。没有一个方法就不会很快。事实上,两个部分索引,一个在系列 1 上,一个在系列 2 上可能会更好。
归档时间: |
|
查看次数: |
297 次 |
最近记录: |