【发布时间】:2021-11-18 16:16:42
【问题描述】:
我需要缓存每个用户第一次、最后一次和倒数第二次发生的事情。我正在查询的历史表有数亿行(我们正在缓存以便我们可以截断它),而我正在更新的表有数千万行。
目前我正在分批执行 1000 个,以避免锁定表。查询是这样的:
with ranked as (
select
user_id,
rank() over (partition by user_id order by created_at desc) as ranked_desc,
rank() over (partition by user_id order by created_at asc) as ranked_asc,
created_at
from history
where type = 'SomeType' and
user_id between $1 and $2
)
update
users u
set
latest_at = (
select created_at
from ranked
where ranked.ranked_desc = 1 and ranked.user_id = u.id
),
previous_at = (
select created_at
from ranked
where ranked.ranked_desc = 2 and ranked.user_id = u.id
),
first_at = (
select created_at
from ranked
where ranked.ranked_asc = 1 and ranked.user_id = u.id
)
from ranked
where u.id = ranked.user_id
历史的相关索引是这些。都是btree索引。
- (created_at)
- (user_id, created_at)
- (用户 ID,类型)
- (类型,created_at)
这可以优化吗?我觉得这可以在没有子查询的情况下完成。
【问题讨论】:
-
使用
rank()代替row_number()有什么特别的原因吗?将为已使用等级中的任何重复项引发异常。另外:请始终声明您的 Postgres 版本并提供包含列类型和约束的基本表定义(CREATE TABLE ...语句)。 -
@ErwinBrandstetter Postgres 13,已标记。我目前在移动设备上,但假设列类型是正常的(时间戳、正确声明的外键等)。感谢关于排名的建议,它不应该出现,但我会换掉它。
-
知道
(user_id, created_at)是否为UNIQUE会有所帮助。 (您对rank()的使用表明了这一点!)或者可以有多个具有相同时间戳的条目? -
@ErwinBrandstetter 这不是唯一索引,但您可以假设它实际上是唯一的。
标签: sql postgresql query-optimization postgresql-performance postgresql-13