Sql 更新大表上的查询速度较慢
我正在尝试更新订单项目中的每一行。Status是新创建的列,必须具有order_update表中的最新值。一个项目可以有多个更新 我正在使用PostgreSQL 9.1 我有这个更新sql。 表order_项有800K条记录。 表order_update有5Mil记录Sql 更新大表上的查询速度较慢,sql,postgresql,sql-update,greatest-n-per-group,postgresql-performance,Sql,Postgresql,Sql Update,Greatest N Per Group,Postgresql Performance,我正在尝试更新订单项目中的每一行。Status是新创建的列,必须具有order_update表中的最新值。一个项目可以有多个更新 我正在使用PostgreSQL 9.1 我有这个更新sql。 表order_项有800K条记录。 表order_update有5Mil记录 update order_item set status = ( select production_stage from order_update where id = ( select
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以最佳方式执行。我知道更新需要一些时间,只是想尽快更新
我发现在5Mil记录上执行此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)
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)
大约需要6秒钟
当我在1Mil记录中执行相同的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;
如果您在Id上有一个包含订单项目Id和生产阶段的订单更新索引,这将很有帮助。 除此之外,这相当简单。使用临时表而不是子查询可能是一种选择,但我看不出还有什么可以改进的。下面的重建呢
update order_item
set status = (
select a.production_stage from (
/********************************************** INNER QUERY START **/
select ou.order_item_id, ou.production_stage
from order_update ou
INNER JOIN (
select order_item_id, max(id) as max_id
from order_update
group by order_item_id
) ou_max ON (ou.order_item_id = ou_max.order_item_id
AND ou.id = ou_max.max_id)
/********************************************** INNER QUERY END **/
) a where a.order_item_id = order_item.id
);
编辑:由于上面的速度较慢,那么下面的代码呢
update order_item
set status = (
select a.production_stage from (
/********************************************** INNER QUERY START **/
select ou.order_item_id, ou.production_stage
from order_update ou
INNER JOIN (
select order_item_id, max(id) as max_id
from order_update
group by order_item_id
) ou_max ON (ou.order_item_id = ou_max.order_item_id
AND ou.id = ou_max.max_id)
/********************************************** INNER QUERY END **/
) a where a.order_item_id = order_item.id
);
在这种情况下,DBMS将只执行一次内部查询以创建临时表A。在此之后,它的行为将类似于:更新订单\项目集状态=从A.order\项目\ id=订单\项目.id;中选择一个.production\阶段;。这将是非常快的,因为A已经创建并作为整个更新的固定表提供-它不是为每个订单项目id重新创建的。我的猜测:这将大大加快速度 问题中的疑问有细微的差别。原来的一个会更新订单项目的每一行。如果在order_update中找不到匹配的行,这将导致状态设置为NULL。此查询只保留这些行的原始值,不进行更新 在这一密切相关的回答中,对带有DISTINCT ON的子查询的详细解释如下: 通常,单个子查询的性能应该比使用相关子查询的方法更好。使用优化的查询更是如此 如果order_item.status应定义为NOT NULL,则最后一行可以简化为 这样的方法可能会有所帮助:
CREATE INDEX order_update_mult_idx ON order_update(order_item_id, id DESC);
第二列的降序是必需的。
但是,由于您在一次扫描中使用了全部或大部分这两个表,索引可能不会有帮助。除了一个,也许,在Postgres 9.2或更高版本中:
CREATE INDEX order_update_mult_idx
ON order_update(order_item_id, id DESC, production_stage);
解释只会给你博士后提出的计划。如果规划师的估算和成本参数设置不准确,这些数字可能会相差很远。要获得实际的性能数据,您必须运行EXPLAIN ANALYSE,这对于大型表来说当然需要很长时间,因为它会测试执行查询。在不熟悉PostgreSQL的情况下,我可能会尝试将聚合查询的结果放在临时表中,然后在UPDATE语句中引用它。您能否确认,看起来您想更新order_items表中所有800k的每条记录。对吗?我这样问是因为感觉状态栏只有在需要时才会在某些记录上更新。你应该用简单的英语解释你想做什么。此外,一如既往,您的Postgres版本和psql中表定义的相关部分\d tbl…这一版本实际上比:更新订单\u项目集状态=从订单中选择生产\u阶段\u更新,其中id=从订单中选择最大id\u更新,其中订单\u项目\u id=订单\u项目.id;