有效地为一个非常大的表中的每个组选择最新行?

Posted

技术标签:

【中文标题】有效地为一个非常大的表中的每个组选择最新行?【英文标题】:Effectively select latest row for each group in a very large table? 【发布时间】:2021-09-21 17:15:07 【问题描述】:

我有(例如)一张桌子Users (user_id, status, timestamp, ...)。 我还有另一张桌子SpecialUsers (user_id, ...)

我需要显示每个特殊用户的最新状态。

问题在于Users非常非常大(超过 50 十亿 行)。例如this question 中的大多数解决方案只是挂起或出现“磁盘已满”错误。

SpecialUsers 表要小得多——“只有”60 万行。

SELECT DISTINCT ON() 不受支持。使用 Amazon RedShift。

编辑:根据请求查看失败的尝试 - 导致磁盘已满错误的其中之一是这样的:

with users_with_status (user_id, status, timestamp)
as (
        select su.user_id, u.instance_type, u.timestamp
        from specialusers su
        join users u on su.user_id = u.user_id
)
select l.instance_id, l.instance_type
from users_with_status l
left outer join users_with_status r
     on l.user_id = r.user_id and l.timestamp < r.timestamp
where r.timestamp is null;

我知道自己正在加入一个错误表,但希望第一次加入小表会减少处理的行数。

无论如何,窗口函数似乎是这里的解决方案。

【问题讨论】:

您能发布您的 SQL 吗?许多磁盘填满的情况是由于不合格的联接或不等式联接子句造成的。这些会导致中间结果中的行爆炸式增长,这就是磁盘填充的原因。 第二。我们猜测没有 DDL 和 SQL。 @BillWeiner 添加了 磁盘被填满的原因可能是 ON 子句“l.timestamp 【参考方案1】:

也许带有窗口功能的join 会起作用:

select su.*
from (select s.user_id, u.status, u.timestamp,
             max(u.timestamp) over (partition by s.user_id) as max_timestamp
      from specialusers s join
           users u
           on s.user_id = u.user_id
     ) su
where timestamp = max_timestamp;

这专门使用max() 而不是row_number(),推测它可能会使用更少的资源。

【讨论】:

谢谢,这基本上搞定了。但是我发现我在大表中有几行具有相同的时间戳,最长可达一微秒:) 所以要尝试 row_number()。我想我也可以使用group by ,它奏效了。没有注意到执行时间的变化。谢谢!

以上是关于有效地为一个非常大的表中的每个组选择最新行?的主要内容,如果未能解决你的问题,请参考以下文章

从 Sqlite 表中选择行的元组并有效地对元组进行排序

有效地为集合中的每个类别选择顶行

从行具有最大日期的表中选择信息

如何从 SQLite 中的表中选择最新的 100 个不同条目?

jquery - 从一个非常大的表中删除所有行的最快方法

从每个 id 具有特定值的表中选择行