1

我有一个我认为具有相当普遍模式的查询。考虑这张表:

id | val | ts
---+-----+-------
 a |  10 | 12:01
 a |  12 | 12:05
 a |   9 | 12:15
 b |  30 | 12:03

我想通过时间戳获取每个 id 的最新值。一些方法可以做到:

-- where in aggregate subquery
-- we avoid this because it's slow for our purposes
select
  id, val
from t
where (id, ts) in
  (select
    id,
    max(ts)
   from t
   group by id);

-- analytic ranking
select
  id, val
from
  (select
    row_number() over (partition by id order by ts desc) as rank,
    id,
    val
  from t) ranked
where rank = 1;

-- distincting analytic
-- distinct effectively dedupes the rows that end up with same values
select
  distinct id, val
from
  (select
    id,
    first_value(val) over (partition by id order by ts desc) as val
  from t) ranked;

分析排名查询感觉像是最容易提出有效查询计划的查询。但在美学和维护方面,它非常难看(尤其是当表的值列不止 1 个时)。在生产中的一些地方,当测试表明性能相当时,我们使用了不同的分析查询。

有没有什么方法可以做 rank = 1 之类的事情而不会得到如此丑陋的查询?

4

2 回答 2

1

如果您只id分组

select
    id, max(ts)
  from x
  group by id 
  order by id

如果该组由idval

select
    id, val, max(ts)
  from
    x
  group by id, val
  order by id, val

所以我不会使用将聚合放在子查询中(可能会更慢)我也不会使用窗口聚合函数(因为你可以用普通的group byand来做max)而且我不会使用distinct,因为这意味着不同的东西(至少对于我)。

如果您对 进行分组id,并且想要的其中一个val,我建议使用窗口聚合函数,因为您必须以某种方式定义 val选择的内容:并且此意图属于order by右后partition by

从维护的角度来看,我认为窗口聚合功能真正描述了您的意图 - 您想要实现的目标。其他查询以某种方式隐藏了他们的意图。就个人而言,当我阅读您的查询时,第二个是最容易理解的。

从性能的角度来看,我可以确认窗口聚合很快(至少在我的情况下)。优化器也可能从语法中受益。

于 2013-06-06T09:44:26.973 回答
1

这是最简单和最快的:

select distinct on (id)
    id, ts, val
from t
order by id, ts desc

distinc on仅限 Postgresql)将只为每个 id 返回一行。用order by你控制哪一个。在这种情况下,最后一个ts. 您可以根据distinct on需要在结果集中包含任意数量的列,而无需中间步骤。中使用的列distinct on必须首先包含在 中order by

于 2013-06-06T11:36:39.070 回答