【问题标题】:PostgreSQL and Python - Improve UPDATE performancePostgreSQL 和 Python - 提高 UPDATE 性能
【发布时间】:2020-03-23 15:35:46
【问题描述】:

我需要更新一个包含 8+ 百万个条目的表,但是下面的语句

UPDATE mytable SET field_3 = 'TEST' WHERE id IN (12, 13, 14, ...., N)

需要很长时间(大约需要更新 180.000 个 ID ---> 2 小时,并且仍在进行中)。

这里是表结构(来自 \d 输出):

 id              | bigint                      | 
 field_1         | bigint                      | 
 field_2         | bigint                      | 
 field_3         | character varying(100)      | 
 ...
 field_N         |                             |

我没有索引或约束。

有什么提高查询性能的想法吗?

谢谢!

【问题讨论】:

    标签: python sql postgresql sql-update


    【解决方案1】:

    评论有点长。

    更新一行需要时间,因为需要完成锁定、日志记录和其他工作。更新大量行可能需要很长时间。

    也就是说,180,000 行的 2 小时似乎很长 - 每秒更新不到 25 次。这种缓慢可能表明资源争用、锁定或过多的触发器和索引需要更新。

    通常,简单地重新创建表更有效:

    create table temp_mytable as
        select . . .,
               (case when id in () then 'TEST' else field_3 end) as field_3, . . . 
        from mytable ;
    
    truncate table mytable;
    
    insert into mytable
        select * from temp_mytable;
    

    【讨论】:

    • 我刚刚尝试了您的解决方案,但 1 小时后的第一步(CREATE TABLE)尚未完成...我认为更新语句很慢...
    【解决方案2】:

    问题在于 IN-lists 没有实现散列方法,因此它对 800 万行中的每一行的 inlist 的 180,000 个值进行迭代。显然这很慢。

    您可以将其重写为 VALUES 列表的连接,这可能会选择散列方法:

    UPDATE my_table SET field_3 = 'TEST' from (values
    (1177703),
    (6803277),
    (6573983),
    (7018535),
    -- 17,994 more 
    (5883920),
    (4581415)) foo(id) where foo.id=my_table.id
    

    在我的手中,这需要 5 秒来更新 800 万行中的 18,000 行。

    【讨论】:

    • 你的例子中的 foo 是什么?请问,你能更好地解释你的方法吗?
    • "foo" 是由 values 列表创建的虚拟表的别名,而 "id" 是该虚拟表中单个列的别名。如果没有别名,它们将是匿名的,因此无法在查询的其余部分中引用,或者分配了无用的默认值。这只是两个特性的组合,值列表 (postgresql.org/docs/current/queries-values.html) 和 UPDATE...FROM (postgresql.org/docs/current/sql-update.html)
    • 类似于创建显式临时表并手动填充 id,然后执行相同的更新连接。我想知道是否有任何性能差异。
    猜你喜欢
    • 1970-01-01
    • 2011-01-06
    • 2021-08-03
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 2022-01-08
    • 2011-09-30
    相关资源
    最近更新 更多