在进行分析查询时如何避免DISTINCT作为拐杖?

时间:2013-06-06 04:14:34

标签: sql postgresql distinct vertica window-functions

我有一个查询,我认为它有一个相当常见的模式。考虑一下这个表:

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这样的东西而不会遇到如此丑陋的查询?

2 个答案:

答案 0 :(得分: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

所以我不会将聚合放在子查询中(可能会更慢) 我也不会使用window agggregate函数(因为你可以使用plain group bymax) 我不会使用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