在PostgreSQL中更新非常大的表而不进行锁定

我有一个很大的表,其中有100M行,我想在其中更新基于另一列的值的列。下面显示了我想做的示例查询:

UPDATE mytable SET col2 = 'ABCD'
WHERE col1 is not null

这是具有多个从属的实时环境中的主数据库,我想在不锁定表或不影响实时环境性能的情况下对其进行更新。什么是最有效的方法?我正在考虑制作一个过程,使用诸如limit之类的东西来批量更新1000或10000行,但是我不太确定该怎么做,因为我对Postgres及其陷阱并不了解。哦,这两列都没有索引,但是表有其他列。

我希望获得示例过程代码。

谢谢。

mm6yuz 回答:在PostgreSQL中更新非常大的表而不进行锁定

没有锁定就没有更新,但是您可以努力使行锁定少而又短。

您可以简单地运行以下命令:

UPDATE mytable
SET col2 = 'ABCD'
FROM (SELECT id
      FROM mytable
      WHERE col1 IS NOT NULL
        AND col2 IS DISTINCT FROM 'ABCD'
      LIMIT 10000) AS part
WHERE mytable.id = part.id;

只需不断重复该语句,直到它修改少于10000行,就可以完成。

请注意,批量更新不会锁定表,但是它们当然会锁定更新的行,而您更新的行越多,事务越长,并且出现死锁的风险也越大。

要使自己表现出色,像这样的索引会有所帮助:

CREATE INDEX ON mytable (col2) WHERE col1 IS NOT NULL;
,

只是开箱即用的想法。 col1和col2都必须为null,以使用索引限定排除项,也许可以构建伪索引。该索引当然会是一个常规表,但只会存在很短一段时间。另外,这减轻了锁定时间的麻烦。

create table indexer (mytable_id integer  primary key);

insert into indexer(mytable_id)
select mytable_id
  from mytable
 where col1 is null
   and col2 is null;

以上内容创建了仅包含合格行的“索引”。现在,将更新/删除语句包装到SQL函数中。此函数将更新主表,并从“索引”中删除更新的行,并返回剩余的行数。

create or replace function set_mytable_col2(rows_to_process_in integer)
returns bigint
language sql
as $$
    with idx as
       ( update mytable
            set col2 = 'ABCD'
          where col2 is null
            and mytable_id in (select mytable_if 
                                 from indexer
                                limit rows_to_process_in
                               )
         returning mytable_id
       )
    delete from indexer
     where mytable_id in (select mytable_id from idx);

    select count(*) from indexer;
$$; 

当函数返回0时,所有初始选择的行均已处理。此时,重复整个过程以拾取最初选择未标识的任何添加或更新的行。应为少量,以后仍需要进行处理。
就像我说的那样,只是一个空想。

已编辑 必须已读入col1所没有的内容。但是想法仍然是一样的,只需更改INSERT语句的“索引器”即可满足您的要求。就在“索引”中进行设置而言,“索引”仅包含一列-大表(及其本身)的主键。
是的,除非您给它提供要处理的行总数作为参数,否则您将需要运行多次。以下是一个可以满足您条件的DO块。每遍处理200,000。根据您的需要进行更改。

Do $$
declare 
    rows_remaining bigint;
begin    
loop
    rows_remaining = set_mytable_col2(200000);
    commit;
    exit when rows_remaining = 0;
end loop;
end; $$; 
本文链接:https://www.f2er.com/2940984.html

大家都在问