首页 > 解决方案 > Postgres:如何并行更新独立列?

问题描述

我用大约 1.2 亿行和几列 ( a,b,c,d) 初始化了一个表。初始化后,我想用一些预先计算的指标来对这些列进行合并,例如a+b, (c+d)/a等。

独立性假设:实际上,指标是非常昂贵的选择和连接,与问题无关。然而,这些指标是完全独立的(即它们可以并行计算,彼此之间没有任何依赖关系)。这就是为什么我想找到一种说服 postgresUPDATE并行执行 s 的方法。

只读约束:在这个过程之后,数据库不会以任何方式被修改,即从现在开始,只会SELECT执行查询。我提到这一点是因为,也许可以稍微放松一下 postgres 锁定系统。

额外列的添加目前分两步执行,如下所示:

  1. 创建列(按顺序):
ALTER TABLE tab ADD "x" ...;
ALTER TABLE tab ADD "y" ...;
...
  1. 使用单个指标更新列。我正在并行执行这些更新(通过协程或子进程):
[query 1] UPDATE tab SET "x" = ...
[query 2] UPDATE tab SET "y" = ...
...

锁:即使我能够在它们的只读SELECT版本中并行运行相同的查询,我也无法执行UPDATEs。从我读过的内容来看,似乎 postgres 正在锁定单个行以进行更新,这对我的情况来说是不幸的。我要么陷入死锁,要么查询在单个核心上执行并且没有加速(基线是按顺序执行查询)。

问题:如何有效地并行执行许多列独立更新?我正在寻找高级答案而不是实际查询。我应该采取什么方法?

我在阅读各种讨论时考虑过的想法:

  1. 找到一种禁用逐行锁的方法,然后在单独的查询中计算每个新列(并行)。或者,告诉 postgres 这些查询可以并行运行。
  2. 计算单个查询中的所有列,但是,将所有行拆分为分离集。然后,为各个行组并行更新这些多列。
  3. 为每一列创建一个新表,计算单个查询中的指标(将结果保存到新表中)。然后,立即从新表中更新最终表。

谢谢!

编辑 1:其中一个查询是 NULL 值的前向填充。另一个基本上是(a-b)/c,然而,更复杂的可以看起来像这样(必须重命名表和列):

CREATE TEMPORARY TABLE tmp_speak AS (  -- faster than subselect below
    SELECT created
    FROM FTable
    WHERE event = 'speak'
);

WITH FDiff AS (
    SELECT r.id AS id,
        (
            SELECT f.t
            FROM tmp_speak AS f
            WHERE r.created <= f.t
            ORDER by f.t ASC
            LIMIT 1
        ) - r.created as next_speak
    FROM RTable as r
    ORDER BY r.id
)
UPDATE RTable
SET next_speak = FDiff.next_speak
FROM FDiff
WHERE RTable.id = FTable.id

标签: postgresqlparallel-processing

解决方案


推荐阅读