【问题标题】:Selecting the latest records by timestampz and groupid通过 timestampz 和 groupid 选择最新的记录
【发布时间】:2017-02-10 11:00:23
【问题描述】:

我正在尝试根据导入时使用的 TIMESTAMPZ 返回商店的最新记录。我在 Postgres 9.5 上,这是我从这里的一些线程的 stackoverflow 中得到的查询:

select p.*
from store_products p
inner join(
   select storeid, sku, max(lastupdated) AS lastupdated
   from store_products
   group by storeid, sku
)sp on p.storeid= sp.storeidand p.lastupdated = sp.lastupdated

这为我提供了每家商店(和 SKU)的最新产品,这很棒(我们有大约 30 家商店),但我注意到查询需要(600 万条记录) 4分钟收集数据。

因此,如果我们将其作为我的数据:

PID | StoreID | SKU | lastupdated
1   | 1       | 1a1 | 2017-02-02 18:22:30
2   | 1       | 1b1 | 2017-02-02 18:21:30
3   | 1       | 1a1 | 2017-01-16 11:22:30
4   | 2       | 1a1 | 2017-02-02 18:21:30
5   | 2       | 1a1 | 2017-02-01 18:21:00
6   | 3       | 1a1 | 2017-02-02 18:21:30
7   | 3       | 1g1 | 2017-02-01 18:21:30

我明白了:

PID | StoreID | SKU | lastupdated
1   | 1       | 1a1 | 2017-02-02 18:22:30
2   | 1       | 1b1 | 2017-02-02 18:21:30
4   | 2       | 1a1 | 2017-02-02 18:21:30
6   | 3       | 1a1 | 2017-02-02 18:21:30

有没有更好的方法让我们能够导入这些商店快照,以便 Postgres 更容易消化上面的查询 - 更快?我们应该添加任何索引吗?这是解释:

Hash Join  (cost=2358424.92..2715814.08 rows=311 width=371)
  Hash Cond: ((lp.storeid = p.storeid) AND (lp.lastupdated = p.lastupdated))
  ->  Subquery Scan on lp  (cost=1676046.30..1737513.85 rows=62125 width=12)
        ->  GroupAggregate  (cost=1676046.30..1736892.60 rows=62125 width=108)
              Group Key: store_products.storeid, store_products.sku
              ->  Sort  (cost=1676046.30..1691102.56 rows=6022505 width=108)
                    Sort Key: store_products.storeid, store_products.sku
                    ->  Seq Scan on store_products  (cost=0.00..297973.05 rows=6022505 width=108)
  ->  Hash  (cost=297973.05..297973.05 rows=6022505 width=371)
        ->  Seq Scan on store_products p  (cost=0.00..297973.05 rows=6022505 width=371)

我们的 Postgres DBA 正在休假,我们中的大多数人并不真正知道在这里做什么。

背景故事...

我们以 JSON 格式获取来自多个商店的商店产品的每日转储。每个商店都由 storeid 确定,它们被导入为一个包含所有商店及其产品的大块 JSON 文件。每个条目都有自己的 lastupdated | TIMESTAMPZ 字段。如果有人决定稍后更新该字段(出于审计目的),这由触发器支持,以自动更新该字段。每天,有大约 2-3K 价值的 store_products 被插入到这个表中,我们目前没有对这些数据进行重复数据删除(所以价格可能已经改变,它可能没有,我们似乎并不关心,我们只是插入)。我想我们很快就会进行重复数据删除。

让我给你一个基本的架构:

CREATE TABLE store_products
(
    id BIGINT DEFAULT PRIMARY KEY NOT NULL,
    storeid INTEGER,
    ...etc etc...
    lastupdated TIMESTAMP WITH TIME ZONE DEFAULT now()
);

storeid 有一个 FK 到 store 表等。

【问题讨论】:

  • "这给了我每家商店的最新产品,...但我真的需要每家商店的所有最新产品" - 我不明白这句话。每个商店只能有一个“最新”产品。请Edit您的问题并添加一些示例数据和基于该数据的预期输出。 Formatted textno screen shots 你检查了greatest-n-per-group 的许多答案吗
  • 会做的,谢谢@a_horse_with_no_name 我会的,是的,这句话有点不对劲......我会用一些样本来修复它,并在查看了我想出的每组最大的数之后上面的查询。我认为我的情况有点不同,因为不幸被 tiemstamp 分开

标签: database postgresql timestamp greatest-n-per-group


【解决方案1】:

distinct on 会更简单:

select distinct on (storeid, sku) *
from store_products
order by storeid, sku, lastupdated desc

请注意,order by 子句对于确定将返回哪一行是强制性的。

在 (storeid, sku, lastupdated) 或仅在 (storeid, sku) 上创建索引(如果没有足够的时间戳值得额外大小的索引)。

【讨论】:

  • 谢谢,语法更简洁,索引也很有帮助。
【解决方案2】:

尝试使用 ROW number -over partition by 子句和使用临时表,如下所示

select *
from (
    select p.*
    from store_products p
    inner join (
        select
            storeid,
            max(lastupdated) AS lastupdated,
            ROW_NUMBER() OVER (PARTITION BY storedid ORDER BY lastupdated DESC) AS RowNo
        from store_products
        group by storeid
    ) sp on p.storeid= sp.storeidand p.lastupdated = sp.lastupdated
) temp
where
order by temp.RowNo 

【讨论】:

  • 感谢您的回复!我更新了我的问题以反映我在第一篇文章中错过的 SKU。
猜你喜欢
  • 2017-03-31
  • 1970-01-01
  • 1970-01-01
  • 2021-05-16
  • 2019-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-22
相关资源
最近更新 更多