我有一个查询,我认为它有一个相当常见的模式。考虑一下这个表:
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这样的东西而不会遇到如此丑陋的查询?
答案 0 :(得分:1)
如果您只按id
分组
select
id, max(ts)
from x
group by id
order by id
如果该论坛由id
和val
select
id, val, max(ts)
from
x
group by id, val
order by id, val
所以我不会将聚合放在子查询中(可能会更慢)
我也不会使用window agggregate函数(因为你可以使用plain group by
和max
)
我不会使用distinct
,因为这意味着不同的东西(至少对我而言)。
如果您对id
进行分组,并且希望一个值val
,我建议使用窗口聚合函数,因为您必须以某种方式定义选择 val
:此意图属于order by
之后的partition by
。
从维护的角度来看,我认为窗口聚合功能确实描述了你的意图 - 你想要实现的目标。其他查询隐藏了他们的意图。就个人而言,当我阅读你的问题时,第二个是最容易理解的问题。
从性能的角度来看,我可以确认窗口聚合很快(至少在我的情况下)。也许优化器也可以从语法中受益。
答案 1 :(得分: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
。