通过 timestampz 和 groupid 选择最新的记录
Selecting the latest records by timestampz and groupid
我正在尝试 return 基于导入时使用的 TIMESTAMPZ 的商店的最新记录。我在 Postgres 9.5 上,这是我在此处的某些线程上从 Whosebuging 获得的查询:
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 家商店),但我注意到查询需要 (对于 6M 记录)大约 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 |时间戳字段。如果有人决定稍后更新该字段(出于审计目的),则由触发器自动更新该字段。每天,大约有 2-3K 的 store_products 被插入到这个 table 中,我们目前没有删除这些数据(所以价格可能已经改变,它可能没有,我们没有似乎还不关心,我们只是插入)。我想我们很快就会删除重复数据。
让我给你一个基本的模式:
CREATE TABLE store_products
(
id BIGINT DEFAULT PRIMARY KEY NOT NULL,
storeid INTEGER,
...etc etc...
lastupdated TIMESTAMP WITH TIME ZONE DEFAULT now()
);
商店的 storeid 有一个 FK table 等等
尝试使用 ROW number -over partition by 子句并使用 temp table,如下所示
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
distinct on
会更简单:
select distinct on (storeid, sku) *
from store_products
order by storeid, sku, lastupdated desc
请注意,必须使用 order by 子句来确定要返回的行。
在 (storeid, sku, lastupdated) 上创建索引,如果没有足够的时间戳值得额外大小的索引,则仅在 (storeid, sku) 上创建索引。
我正在尝试 return 基于导入时使用的 TIMESTAMPZ 的商店的最新记录。我在 Postgres 9.5 上,这是我在此处的某些线程上从 Whosebuging 获得的查询:
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 家商店),但我注意到查询需要 (对于 6M 记录)大约 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 |时间戳字段。如果有人决定稍后更新该字段(出于审计目的),则由触发器自动更新该字段。每天,大约有 2-3K 的 store_products 被插入到这个 table 中,我们目前没有删除这些数据(所以价格可能已经改变,它可能没有,我们没有似乎还不关心,我们只是插入)。我想我们很快就会删除重复数据。
让我给你一个基本的模式:
CREATE TABLE store_products
(
id BIGINT DEFAULT PRIMARY KEY NOT NULL,
storeid INTEGER,
...etc etc...
lastupdated TIMESTAMP WITH TIME ZONE DEFAULT now()
);
商店的 storeid 有一个 FK table 等等
尝试使用 ROW number -over partition by 子句并使用 temp table,如下所示
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
distinct on
会更简单:
select distinct on (storeid, sku) *
from store_products
order by storeid, sku, lastupdated desc
请注意,必须使用 order by 子句来确定要返回的行。
在 (storeid, sku, lastupdated) 上创建索引,如果没有足够的时间戳值得额外大小的索引,则仅在 (storeid, sku) 上创建索引。