Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 更新大表上的查询速度较慢_Sql_Postgresql_Sql Update_Greatest N Per Group_Postgresql Performance - Fatal编程技术网

Sql 更新大表上的查询速度较慢

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

我正在尝试更新订单项目中的每一行。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 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;