【发布时间】:2013-11-27 00:42:19
【问题描述】:
我正在尝试更新 order_item 中的每一行。 Status 是一个新创建的列,并且必须具有 order_update 表中的最新值。一个项目可以有多个更新。
我使用的是 PostgreSQL 9.1
我有这个更新 sql。order_item 表有 800K 条记录。
表 order_update 有 5 百万条记录。
update order_item
set status = (
select production_stage
from order_update
where id = (
select max(id)
from order_update
where order_item_id = order_item.id
)
);
我怎样才能让这个 sql 以最好的方式执行。我知道更新需要一些时间,我只想尽快更新。
我发现在 50 万条记录上执行此 sql 时。
select max(id) from order_update where order_item_id = 100;
解释:
Result (cost=784.10..784.11 rows=1 width=0)" InitPlan 1 (returns $0)
-> Limit (cost=0.00..784.10 rows=1 width=8)
-> Index Scan Backward using order_update_pkey on order_update (cost=0.00..104694554.13 rows=133522 width=8)
Index Cond: (id IS NOT NULL)
Filter: (order_item_id = 100)
大约需要 6 秒。
当我在 10 万条记录中执行相同的 sql 时:
解释:
Aggregate (cost=13.43..13.44 rows=1 width=8) -> Index Scan using
order_update_order_item_id_idx on order_update (cost=0.00..13.40
rows=11 width=8)
Index Cond: (order_item_id = 100)
大约需要 11 毫秒。
11 毫秒与 6 秒。为什么会有这么大的差异?
为了缩小范围,我试试这个:
select id from order_update where order_item_id = 100 order by id asc
limit 1
Total query runtime: 41 ms.
然后这个:
select id from order_update where order_item_id = 100 order by id desc
limit 1
Total query runtime: 5310 ms.
所以 asc 和 desc 的差异很大。
解决方案: 创建索引:
CREATE INDEX order_update_mult_idx ON order_update (order_item_id, id DESC);
更新:
UPDATE order_item i
SET test_print_provider_id = u.test_print_provider_id
FROM (
SELECT DISTINCT ON (1)
test_print_provider_id
FROM orders
ORDER BY 1, id DESC
) u
WHERE i.order_id = u.id
AND i.test_print_provider_id IS DISTINCT FROM u.test_print_provider_id;
【问题讨论】:
-
如果不熟悉 PostgreSQL,我可能会尝试将聚合查询的结果放在临时表中,然后在
UPDATE语句中引用它。 -
您能否确认一下,您似乎想更新
order_items表中的每条记录(全部为 800k)。那是对的吗?我问是因为感觉“状态”列只会在需要时更新某些记录。 -
你应该解释(用简单的英语)你想要做什么。此外,与往常一样,您的 Postgres 版本和表定义的相关部分(psql 中的
\d tbl)...
标签: sql postgresql sql-update greatest-n-per-group postgresql-performance