DO $$
DECLARE
batch_size integer := 30000; -- Adjust the batch size as needed
BEGIN
FOR i IN 0..(SELECT ceil(count(*)::numeric / batch_size) FROM message) LOOP
UPDATE message m
SET user_id = u.id
FROM "user" u
WHERE u.user_pgid = m.user_pgid
LIMIT batch_size
OFFSET i * batch_size;
END LOOP;
END $$;
2条答案
按热度按时间58wvjzkj1#
仅限
SELECT
的并行查询计划Postgres只对
SELECT
使用并行计划(以及一些基于SELECT
的命令,如CREATE TABLE AS
)。无法并行修改任何行。The manual:即使通常可以生成并行查询计划,如果满足以下任一条件,计划程序也不会为给定查询生成并行查询计划:
手动并行
回答你的问题:沿着沿着
user_pgid
将表分割成 N 个不重叠的切片,切片大小大致相等-其中 N 是并行使用的进程数。不应超过可用的CPU核心数。总的来说,保持低于DB服务器的I/O容量。创建一个
PROCEDURE
,如下所示:字符串
电话:
型
或者:
型
①避免空更新(列值不会改变)。如果
user_id
可以为null,请使用与IS DISTINCT FROM
的空安全比较。还可以防止重复更新,以防您必须重新开始或弄乱切片。请参阅:
将切片基于 * 实际 * 最小和最大
user_pgid
:型
根据你的系统调整
_step
的大小。我添加了默认值50000。然后运行 N 个单独的会话,每个会话处理一个切片。比如,启动 N 个psql示例(手动或在shell脚本中)。
每一步都是提交的。如果你仍然遇到超时(或任何其他问题),提交的工作不会回滚。
相关:
副作用、注意事项
由于每次更新都会留下一个死元组,因此表的大小将增加两倍。如果你有能力,你可能想在之后运行
VACUUM FULL
。或者,在过程中以合理的间隔发出VACUUM
,以从死元组中腾出空间供重用。请参阅:其他各种优化都是可能的。比如删除并稍后重新创建FK约束,索引,.但是你绝对需要在
message(user_pgid)
上**索引!如果你可以这么做,那么创建一个更新的(排序的?)表副本,而不是更新所有行。就像Frank已经建议的那样。这会给你一个没有膨胀的原始(集群)表。
gcuhipw92#
要加快对大型表的更新操作,可以尝试一些技术来优化查询:
批量处理您可以在较小的批中更新记录,而不是在单个事务中更新所有记录。这可以减少对系统资源的影响,并有助于避免超时。
批处理的示例实现:
字符串