如何在不锁定 table 的情况下回填 Postgres 中的列?
How to backfill column in Postgres without locking the table?
我最近在我的 40+ 百万行 Postgres table (v9.6) 中添加了一个新专栏
ALTER TABLE queries
ADD COLUMN ml_partition_source UUID;
然后在我执行的另一笔交易中
ALTER TABLE queries
ALTER COLUMN ml_partition_source
SET DEFAULT public.gen_random_uuid();
我在两个事务中完成了此操作,因为在新列上设置 default
会导致 Postgres 重写整个 table,这可能需要数小时并且无法接受 table生产中。
现在,我想在不锁定 table 的情况下为添加新列之前存在的所有 query
回填此列。一种方法是通过 CRUD API 我有,但一些粗略的计算表明这将需要大约 22 天(也许我的 API 性能可以提高,但这是一个完全不同的问题)。相反,我尝试编写一个 postgres 函数:
CREATE OR REPLACE FUNCTION backfill_partition_source()
RETURNS void AS $$
declare
query_ record;
BEGIN
for query_ in
select * from api_mldata.queries where ml_partition_source is null
loop
update api_mldata.queries SET ml_partition_source = public.gen_random_uuid() where id = query_.id;
end loop;
END;
$$ LANGUAGE plpgsql;
并用 select backfill_partition_source();
执行。但这最终也锁定了 table。
如何在不影响生产(或对生产影响最小)的情况下回填列?
编辑:我的一个想法是 "chunking" Postgres 脚本一次操作 100k 行或类似的东西,然后循环执行脚本。所以 select 语句将变成
select * from api_mldata.queries
where ml_partition_source is null
limit 100000;
不上锁根本无法逃脱,但可以将锁保持在适当的短。
而不是 运行在循环中进行许多单行更新,运行 更大的更新:
UPDATE api_mldata.queries
SET ml_partition_source = DEFAULT
WHERE id BETWEEN 1 AND 999999;
这里id
是table的主键。
这样您就可以完成一些更大的更新,每个更新都针对不同的 id
范围。
为了避免膨胀和过度锁定,运行 每个语句在其自己的事务中并在语句之间的 table 上启动显式 VACUUM
。
我最近在我的 40+ 百万行 Postgres table (v9.6) 中添加了一个新专栏
ALTER TABLE queries
ADD COLUMN ml_partition_source UUID;
然后在我执行的另一笔交易中
ALTER TABLE queries
ALTER COLUMN ml_partition_source
SET DEFAULT public.gen_random_uuid();
我在两个事务中完成了此操作,因为在新列上设置 default
会导致 Postgres 重写整个 table,这可能需要数小时并且无法接受 table生产中。
现在,我想在不锁定 table 的情况下为添加新列之前存在的所有 query
回填此列。一种方法是通过 CRUD API 我有,但一些粗略的计算表明这将需要大约 22 天(也许我的 API 性能可以提高,但这是一个完全不同的问题)。相反,我尝试编写一个 postgres 函数:
CREATE OR REPLACE FUNCTION backfill_partition_source()
RETURNS void AS $$
declare
query_ record;
BEGIN
for query_ in
select * from api_mldata.queries where ml_partition_source is null
loop
update api_mldata.queries SET ml_partition_source = public.gen_random_uuid() where id = query_.id;
end loop;
END;
$$ LANGUAGE plpgsql;
并用 select backfill_partition_source();
执行。但这最终也锁定了 table。
如何在不影响生产(或对生产影响最小)的情况下回填列?
编辑:我的一个想法是 "chunking" Postgres 脚本一次操作 100k 行或类似的东西,然后循环执行脚本。所以 select 语句将变成
select * from api_mldata.queries
where ml_partition_source is null
limit 100000;
不上锁根本无法逃脱,但可以将锁保持在适当的短。
而不是 运行在循环中进行许多单行更新,运行 更大的更新:
UPDATE api_mldata.queries
SET ml_partition_source = DEFAULT
WHERE id BETWEEN 1 AND 999999;
这里id
是table的主键。
这样您就可以完成一些更大的更新,每个更新都针对不同的 id
范围。
为了避免膨胀和过度锁定,运行 每个语句在其自己的事务中并在语句之间的 table 上启动显式 VACUUM
。