我有一个测量数据库,表明传感器,读数和读数的时间戳。只有在发生变化时才会记录测量结果。我想生成一个结果集,显示每个传感器读取特定测量值的范围。
时间戳以毫秒为单位,但我在几秒钟内输出结果。
这是表格:
CREATE TABLE `raw_metric` (
`row_id` BIGINT NOT NULL AUTO_INCREMENT,
`sensor_id` BINARY(6) NOT NULL,
`timestamp` BIGINT NOT NULL,
`angle` FLOAT NOT NULL,
PRIMARY KEY (`row_id`)
)
现在我正在使用子查询得到我想要的结果,但是当有很多数据点时,它相当慢:
SELECT row_id,
HEX(sensor_id),
angle,
(
COALESCE((
SELECT MIN(`timestamp`)
FROM raw_metric AS rm2
WHERE rm2.`timestamp` > rm1.`timestamp`
AND rm2.sensor_id = rm1.sensor_id
), UNIX_TIMESTAMP() * 1000) - `timestamp`
) / 1000 AS duration
FROM raw_metric AS rm1
基本上,要获得范围,我需要获得下一个读数(或者如果没有其他读数则使用当前时间)。子查询找到的最小时间戳晚于当前的时间戳,但来自同一传感器。
此查询不会经常发生,因此我不希望在时间戳列上添加索引并减慢插入速度。我希望有人可能会建议另一种方法。
更新 row_id的应随时间戳递增,但由于网络延迟问题,无法保证。因此,有可能在较晚的row_id之后出现具有较低row_id的条目,尽管不太可能。
答案 0 :(得分:1)
这可能更适合作为评论而非解决方案,但评论时间太长了。
您正在尝试在MySQL中实现lead()
函数,遗憾的是,MySQL没有窗口函数。您可以切换到Oracle,DB2,Postgres,SQL Server 2012并在那里使用内置(和优化)功能。好的,这可能不太现实。
因此,根据您的数据结构,您需要执行相关子查询或非等值连接(实际上是部分等连接,因为sensor_id
上存在匹配)。除非添加索引,否则这些操作将是昂贵的操作。除非你每秒增加几十次测量,否则索引的额外开销不应该是一个大问题。
您还可以更改数据结构。如果您有一个“传感器计数器”,它是一个枚举读数的序列号,那么您可以将其用作等值连接(尽管为了获得良好的性能,您可能仍需要索引)。将此添加到您的表中需要具有触发器 - 并且这可能比插入时的索引更糟糕。
如果您只有少量传感器,则可以为每个传感器创建一个单独的表。哦,我能感受到这个建议的呻吟声。但是,如果你这样做,那么自动增加的id将执行相同的角色。说实话,如果我能计算每只手上的传感器数量,我只会这样做。
最后,我可能会建议您在插入期间接受命中,并在每条记录上有“有效”和“结束”时间(以及传感器ID和时间戳或ID的索引)。使用这些附加列,您可能会发现该表的更多用途。
如果您只为一个传感器执行此操作,则为信息创建一个临时表并使用自动增加的id列。然后将数据插入其中:
insert into temp_rawmetric (orig_row_id, sensor_id, timestamp, angle)
select orig_row_id, sensor_id, timestamp, angle
from raw_metric
order by sensor_id, timestamp;
确保您的表具有自动递增的temp_rawmetric_id
列和主键(自动创建索引)。 order by
确保根据时间戳递增。
然后您可以按以下方式进行查询:
select trm.sensor_id, trm.angle,
trm.timestamp as startTime, trmnext.timestamp as endTime
from temp_rawmetric trm left outer join
temp_rawmetric trmnext
on trmnext.temp_rawmetric_id = trm.temp_rawmetric_id+1;
这将需要传递原始数据以添加数据,然后在临时表上进行主键连接。第一个可能需要一些时间。第二个应该很快。
答案 1 :(得分:0)
如果对主键使用auto_increment,则可以在查询条件部分中将row_id替换为time_amp。像这样:
SELECT row_id,
HEX(sensor_id),
angle,
(
COALESCE((
SELECT MIN(`timestamp`)
FROM raw_metric AS rm2
WHERE rm2.`row_id` > rm1.`row_id`
AND rm2.sensor_id = rm1.sensor_id
), UNIX_TIMESTAMP() * 1000) - `timestamp`
) / 1000 AS duration
FROM raw_metric AS rm1
它必须快速运作。
此外,您还可以为新的传感器值的快速选择行ID添加一个子查询。参见:
SELECT row_id,
HEX(sensor_id),
angle,
(
COALESCE((
SELECT timestamp FROM raw_metric AS rm1a
WHERE row_id =
(
SELECT MIN(`row_id`)
FROM raw_metric AS rm2
WHERE rm2.`row_id` > rm1.`row_id`
AND rm2.sensor_id = rm1.sensor_id
)
), UNIX_TIMESTAMP() * 1000) - `timestamp`
) / 1000 AS duration
FROM raw_metric AS rm1
答案 2 :(得分:0)
Select rm1.row_id
,HEX(rm1.sensor_id)
,rm1.angle
,(COALESCE(rm2.timestamp, UNIX_TIMESTAMP() * 1000) - rm1.timestamp) as duration
from raw_metric rm1
left outer join
raw_metric rm2
on rm2.sensor_id = rm1.sensor_id
and rm2.timestamp = (
select min(timestamp)
from raw_metric rm3
where rm3.sensor_id = rm1.sensor_id
and rm3.timestamp > rm1.timestamp
)