【问题标题】:Copying timestamp columns within a Postgres table在 Postgres 表中复制时间戳列
【发布时间】:2015-09-20 17:13:55
【问题描述】:

我在 Postgres 9.4 db 中有一个包含大约 3000 万行的表。该表有 6 列,主键 id、2 个文本、一个布尔值和两个时间戳。其中一个文本列上有索引,显然是主键。

我想复制第一个时间戳列中的值,将其命名为 timestamp_a 到第二个时间戳列,命名为 timestamp_b。为此,我运行了以下查询:

UPDATE my_table SET timestamp_b = timestamp_a;

这行得通,但需要一个小时 15 分钟才能完成,这对我来说似乎真的很长,据我所知,它只是将值从一列复制到下一列。

我在查询中运行了EXPLAIN,似乎没有什么特别低效的。然后我使用pgtune 来修改我的配置文件,最明显的是它增加了shared_bufferswork_memmaintenance_work_mem

我重新运行了查询,它所用的时间基本相同,实际上稍长一些(一小时 20 分钟)。

我还能做些什么来提高此更新的速度?这只是将 3000 万个时间戳写入 postgres 需要多长时间吗?对于上下文,我在 macbook pro、osx、quadcore、16 gigs 的 ram 上运行它。

【问题讨论】:

  • 复制列是否有索引?如果不在索引记录上尝试相同的查询
  • @NavasBasheer:如果您更新所有行,索引将无济于事。实际上,索引会减慢更新速度。 Steve:如果timestamp_b 上有索引,那么在运行更新之前删除该索引。
  • @a_horse_with_no_name:感谢您的信息
  • 首先我会尝试增量更新。您可以在 interesting post 中了解此方法和其他方法。
  • @klin 感谢这篇文章,我会尝试其中一些策略。

标签: sql postgresql


【解决方案1】:

这很慢的原因是内部 PostgreSQL 没有更新该字段。它实际上用新值写入新行。这通常需要与 inserting 那么多值相似的时间。

如果 any 列上有索引,这可能会进一步减慢更新速度。即使它们不在正在更新的列上,因为 PostgreSQL 必须写入新行并写入新的索引条目以指向该行。 HOT 更新可以提供帮助,并且会在可用时自动执行此操作,但这通常仅在表受到大量小更新时才有帮助。如果对任何正在更新的字段进行索引,它也会被禁用。

由于您基本上是在重写表,如果您不介意在执行此操作时锁定所有并发用户,您可以通过以下方式更快地完成:

  • BEGIN
  • DROP所有索引
  • UPDATE餐桌
  • CREATE再次全部索引
  • COMMIT

PostgreSQL 还对刚刚被 TRUNCATEd 的表的写入进行了优化,但要从中受益,您必须将数据复制到临时表,然后将 TRUNCATE 复制回来。所以没有任何好处。

【讨论】:

    【解决方案2】:

    @Craig mentionedTRUNCATE 之后对COPY 的优化:Postgres 可以跳过 WAL 条目,因为如果事务失败,无论如何没人会看到新表。

    同样的优化也适用于使用CREATE TABLE AS 创建的表:

    您的描述中缺少详细信息,但是如果您有能力编写一个新表(没有并发事务妨碍,没有依赖项),那么最快的方法可能是(除非您有大 TOAST 表条目 - 基本上大列):

    BEGIN;
    LOCK TABLE my_table IN SHARE MODE;  -- only for concurrent access
    
    SET LOCAL work_mem = '???? MB';  -- just for this transaction
    
    CREATE my_table2
    SELECT ..., timestamp_a, timestamp_a AS timestamp_b
           -- columns in order, timestamp_a overwrites timestamp_b
    FROM   my_table
    ORDER  BY ??;  -- optionally cluster table while being at it.
    
    DROP TABLE my_table;
    ALTER TABLE my_table2 RENAME TO my_table;
    
    ALTER TABLE my_table
     , ADD CONSTRAINT my_table_id_pk PRIMARY KEY (id);
    
    -- more constraints, indices, triggers?
    -- recreate views etc. if any
    
    COMMIT;
    

    额外的好处:一个没有膨胀的原始(可选集群)表。相关:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-24
      • 2019-04-29
      • 2013-01-14
      • 1970-01-01
      • 1970-01-01
      • 2016-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多