【问题标题】:SQL - how can I efficiently select multiple closest time series data pointsSQL - 如何有效地选择多个最接近的时间序列数据点
【发布时间】:2015-08-22 14:23:56
【问题描述】:

我有一个简单的表 data 来记录具有列 recorded_at DateTime 和 value Integer 的数据流。数据不是定期分布的,每分钟可能有多行,或者几个小时没有。

如果我想选择单个值,此查询非常适合我的目的,选择比我正在搜索的位置更接近的结果:

select * from data where recorded_at > '2015-01-01 01:01:01' limit 1

但是,除了使用上述重复查询的联合之外,我找不到一种有效的方法来选择最接近多个搜索日期的单个行,如果我想选择几百个点,这会创建一个巨大的查询。例如,如果我想要最接近“2015-01-01 01:01:01”的单行以及“2015-02-02 02:02:02”。

有没有更好的方法来做到这一点?

基本上我所追求的伪查询是:

select * from data where recorded_at NEAR (date1, date2, date3) NEAR 像 IN 一样工作,但更模糊,因为我事先不知道确切的日期。

【问题讨论】:

  • 那么你想要的是n 最接近的结果,而不仅仅是1?
  • 不,我在寻找与 N 个不同搜索日期最接近的 1 个结果,我会澄清这个问题。
  • 假设表中有 6 个日期,recorded_at 值(1、2、4、5、6、7),您需要最接近 2 和 6 的日期。结果应该是什么?
  • 我不确定我是否理解您的要求。我编辑了我的问题,希望能更清楚。
  • 我在问NEAR 应该如何工作。它应该只返回最接近所有日期的 1 条记录,还是应该在每个日期返回 1 条记录,每条记录最接近集合中提供的日期?

标签: mysql sql


【解决方案1】:

要获得多个积分:

select d.* 
from data d
where recorded_at > '2015-01-01 01:01:01'
order by recorded_at
limit 100

为了有效地获取它们,请在 data(recorded_at) 上创建索引:

create index idx_data_recorded_at on data(recorded_at);

另外,union 可能不会对您的事业有所帮助。尽管没有order bylimit 不能保证返回任何特定的行,但它通常会一遍又一遍地返回同一行。

编辑(基于问题编辑):

对于多个日期,这变得有点困难。你可能最好使用union all

(select d.* 
 from data d
 where recorded_at > '2015-01-01 01:01:01'
 order by recorded_at
 limit 1
) union all
(select d.* 
 from data d
 where recorded_at > '2015-02-01 01:01:01'
 order by recorded_at
 limit 1
)

虽然很复杂,但每个子查询在正确的索引下应该非常快,因此整个查询应该非常快。

【讨论】:

  • 联合是我现在所在的位置,但是如果我想找到最接近 100 个日期的行,则查询会变大(或者我需要进行 100 个单独的查询,这比线)。
  • @EJ01 。 . .您发出的是一个查询,而不是 100 个。一个包含 100 个子查询的查询。
  • 是的,联合它是一个查询,而且速度非常快,我只是担心查询本身变得太大(例如,如果我尝试选择 1000 个日期)。也许我正试图过度优化它。
  • @EJ01 。 . . 1,000 个日期将是很多天。
【解决方案2】:

您需要订购

select * from data 
where recorded_at > '2015-01-01 01:01:01' and recorded_at < '2015-01-02 01:01:01' 
order by recorded_at limit 1

这是在 OP 编辑​​他的问题后编辑的

如果您想拥有多个日期并希望为每个日期获取最接近的日期,我建议您使用包含所有搜索日期的查找表并尝试以下操作。 keycol 是表数据中的唯一列

select t1.* from
(
select t.keycol,min(t.recorded_at) as recorded_at from data as t inner join
lookup_table as dates on t.recorded_at>look.recorded_at
group by t.keycol
) as t2 on t1.keycol=t2.keycol and t1.recorded_at=t2.recorded_at

【讨论】:

  • 将“limit 1”替换为“limit 100”以获得最近的 100 个数据点 > 2015-01-01 01:01:01
  • 我稍微编辑了我的问题。我只在最接近多个搜索日期的单行之后,例如最接近“2015-01-01”的行和最接近“2015-02-02”的行。
  • 我不是在寻找两个日期之间的行,而是在寻找最接近搜索日期列表的各个行。基本上是一种重复我的单查询示例的方法,而无需多次执行该查询。
【解决方案3】:

以下查询选择最接近每个日期的日期:

select d1.recorded_at rec_at, d2.recorded_at closest, min(d2.recorded_at - d1.recorded_at) difference
from data d1, data d2
where d1.recorded_at in ('2015-01-01 01:01:01', '2015-02-01 01:01:01', ...)
      and d2.recorded_at > d1.recorded_at
group by d1.recorded_at

【讨论】:

  • 如果我从一行中为 IN 部分选择一个日期,它将返回结果,但如果我选择接近它的日期则不会。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-20
  • 2017-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多