我想更新postgres表的一列。记录约为5500万,所以我们需要在一批10000条记录中更新它。注意:我们想更新所有的行,但是我们不想锁定我们的表。
我正在尝试以下查询-
Update account set name = Some name where id between 1 and 10000
我们怎样才能每更新10000条记录就循环一次呢?
如有任何建议和帮助,我们将不胜感激。
PostgreSQL 10.5版本
我想更新postgres表的一列。记录约为5500万,所以我们需要在一批10000条记录中更新它。注意:我们想更新所有的行,但是我们不想锁定我们的表。
我正在尝试以下查询-
Update account set name = Some name where id between 1 and 10000
我们怎样才能每更新10000条记录就循环一次呢?
如有任何建议和帮助,我们将不胜感激。
PostgreSQL 10.5版本
4条答案
按热度按时间kmbjn2e31#
与其一次提交所有更改(或者像其他答案中建议的那样提交5500万次),我宁愿尝试将更新行分成小批,例如您建议的10k条记录。在PL/pgSQL中,可以使用关键字
BY
以给定的步骤迭代集合。因此,您可以在anonymous code block
中执行批更新,如下所示:PostgreSQL 11+版本
WHERE
子句以避免不必要的重叠。测试
具有1051行的数据样本,这些行具有连续ID:
正在执行匿名代码块...
..您可以成批更新行。为了证明我的观点,下面的查询计算按更新时间分组的记录数:
演示:
db<>fiddle
mrzz3bfm2#
您可以使用procedure(从版本11开始提供),然后逐个执行,如下所示:
vh0rcniy3#
设置测试环境:
更新脚本:
tjjdgumg4#
但我们不想锁定我们的表。
在许多情况下都有意义,但您没有公开您的实际设置。您是否需要锁?是否存在并发写入活动?如果没有,是否有足够的存储空间写入表的另一个副本?然后,最好在后台构建一个新的原始更新表,然后切换并删除旧表。请参阅:
假设对表的并发写操作,你不想阻塞太多的写操作太长时间,你想重用死元组来防止表膨胀和索引膨胀,所以批量更新是有意义的,你必须
COMMIT
(和VACUUM
),以便可以重用死元组所占用的空间。并在表中分散写操作,以允许连续的事务在相同的块中产生和使用死元组。在Postgres 11或更高版本中,允许在
DO
语句的过程或匿名代码块中使用事务控制语句(如COMMIT
)。其他人回答提供了使用该语句的解决方案。autovacuum
应使用积极的设置运行,以及时释放失效的元组以便重新使用。或者以一定的间隔手动运行VACUUM
-但(当前)根本无法在事务上下文中运行(只能作为单个命令),因此无法在PL/pgSQL循环中运行。Postgres 10岁或以上
代码块中还不允许事务控制。不过我们可以用
dblink
模拟自治事务。请参见:可能类似于:
我还添加了另一个 predicate :
跳过行已具有新名称的空更新的成本。仅在这种情况下才有用。请参阅:
您可能希望进一步拆分它,并在它们之间运行
VACUUM
,并且您可能希望使用id
之外的其他列(未聚集的列)进行选择,以便在整个表中获得良好的分布。