【问题标题】:Is there any way to update this column faster using PostgreSQL有什么方法可以使用 PostgreSQL 更快地更新此列
【发布时间】:2023-05-12 08:01:01
【问题描述】:

我有大约 200,000,000 行,我正在尝试更新其中一列,这个查询似乎特别慢,所以我不确定到底是哪里出了问题,或者只是速度很慢。

UPDATE table1 p
SET    location = a.location
FROM   table2 a
WHERE  p.idv = a.idv;

我目前正在为两张桌子使用 idv。有什么办法可以加快速度吗?

【问题讨论】:

  • 为什么一开始就复制数据?如果您确实需要该位置,您不能只从 table1 中删除列并简单地加入 table2 吗?
  • 为了降低对数据库的性能影响,您可以将更新拆分为更小的块。你更新整张桌子吗?如果您更新大部分表,您可以创建具有相同结构的新表并在该表中选择新数据,更改切换表名称,然后丢弃旧表。
  • 更新 200,000,000 行需要一段时间。如果不量化这种缓慢,就无法知道它是常见的还是异常的。
  • @jjanes 它已经过了一夜,所以大概有 10 个小时,它还没有完成
  • 如果某些数据不需要更新,那么在 WHERE 中检查可以减少写入。前任。 WHERE p.idv = a.idv and p.location <> a.location

标签: postgresql


【解决方案1】:

几周前遇到同样的问题,最后我使用以下策略来大幅提高速度。我想这不是最好的方法,但仅供您参考。

  1. 编写一个简单的函数来接受一个 ID 范围。该函数将执行更新 SQL,但只是更新这些 ID 范围。

  2. 还将 'location != a.location' 添加到 where 子句。听说可以减少表膨胀影响查询性能,需要做vacuum来恢复性能。

我使用大约 30 个线程连续执行该函数,直觉上我认为它可以将所需的总时间减少大约 30 倍。如果您有足够的野心,您可以调整以使用更多的线程。

所以它同时执行下面的操作:

update table1 p set location = a.location from table a where p.idv = a.idv and location != a.location and p.id between 1 and 100000;
update table1 p set location = a.location from table a where p.idv = a.idv and location != a.location and p.id between 100001 and 200000;
update table1 p set location = a.location from table a where p.idv = a.idv and location != a.location and p.id between 200001 and 300000;
.....
.....

另外它还有一个好处是我可以通过在每个函数中打印一些简单的计时统计信息来了解更新进度以及估计的剩余时间。

【讨论】:

    【解决方案2】:

    创建新表比更新现有数据要快。因此,您可以尝试以下方法:

    CREATE TABLE new_table AS
      SELECT
        a.*, -- here you can set all fields you need
        CALESCE(b.location, a.location) location -- update location field from table2
      FROM table1 a
      LEFT JOIN table2 b ON b.idv = a.idv;
    

    创建后,您将能够删除旧表并重命名新表。

    【讨论】:

    • 不能忘记索引、约束和可能的其他依赖对象,例如触发器、视图……和检查授权?