假设我有下表log
。它描述了一系列与序列号相关的带时间戳的事件。有各种事件类型列,此处只显示了2列 - session_started
和voltage_changed
。在每一行中,只有一个非空的事件类型。所有行都包含非空serial
和time_stamp
字段。第一行将两种事件类型都设置为NULL,这意味着其他事件类型列之一(未显示)包含一个值(它有助于代表性示例)。
我想找到发生的每个session_started
事件,记录下一个voltage_changed
值(按时间戳记)。这是数据:
serial || time_stamp || session_started || voltage_changed
BBBB | 2017-12-15 03:05:55 | NULL | NULL |
AAAA | 2017-12-15 04:05:55 | 1 | NULL |
AAAA | 2017-12-15 04:30:55 | NULL | 127 |
AAAA | 2017-12-15 05:15:55 | NULL | 75 |
BBBB | 2017-12-15 05:20:55 | 1 | NULL |
BBBB | 2017-12-15 06:00:55 | NULL | 10 |
期望的结果:
serial || time_stamp || voltage
AAAA | 2017-12-15 04:05:55 | 127 |
BBBB | 2017-12-15 05:20:55 | 10 |
这是我试过的查询。它在这个示例表上工作并生成正确的结果,但是在整个表上运行需要很长时间(我厌倦了等待查询完成执行...)完整表有190,000行并且有一个索引on time_stamp。
SELECT
h.serial,
h.time_stamp,
hh.voltage_changed AS voltage
FROM
log h,
log hh
WHERE
h.serial = hh.serial
AND hh.time_stamp = (SELECT MIN(hh.time_stamp)
FROM log hh
WHERE (hh.time_stamp >= h.time_stamp)
AND hh.voltage_changed IS NOT NULL
AND (h.session_started = 1));
有没有办法优化此查询以便在大型表上更有效地工作?在time_stamp上有一个索引就足够了,还是应该考虑这个实例中的其他列?
答案 0 :(得分:2)
因为您只想要一列,我认为自连接是不必要的。我首先将其写为相关子查询:
select l.*,
(select l2.voltage_changed
from log l2
where l2.serial = l.serial and
l2.time_stamp >= l.time_stamp and
l2.voltage_changed is not null
order by l2.time_stamp asc
limit 1
) as voltage_changed
from log l
where l.session_started = 1;
为此,您需要两个索引。更重要的是log(serial, voltage_changed, time_stamp)
。第二个是log(session_started, serial)
。
答案 1 :(得分:1)
我会将您的数据重新整理为voltage_changed
结构,以便您在event_type
列中包含event_value
,event_type
或其他值,以及与该关联的任何整数值serial
列中的事件。由serial
和voltage_changed
编制索引,select
t1.serial,
t1.time_stamp,
t2.event_value as voltage
from (
select
e1.serial,
e2.time_stamp,
min(e3.timestamp) AS voltage_ts
from log e1
left join log e2
on e1.serial=e2.serial
and e1.time_stamp<=e2.time_stamp
and e2.event_type='voltage_changed'
where e1.event_type='session_started'
and e1.event_value=1
group by 1,2
) t1
join log t2
on t1.serial=t2.serial
and t1.voltage_ts=t2.time_stamp
and t2.event_type='voltage_changed';
为聚集索引。
在这种情况下,必须有效地过滤必要的行,而不必扫描整个表中的O(1)
列的非空值以进一步自我加入。
然后你的查询就像(与相关子查询一起工作):
HashMap
我知道保留这些数据可能是有效的考虑因素,只是提供另一种观点。