Postgresql 如何在不锁定表的情况下在Postgres中回填列?
最近,我在我的4000多万行Postgres表v9.6中添加了一个新的列Postgresql 如何在不锁定表的情况下在Postgres中回填列?,postgresql,bulkupdate,Postgresql,Bulkupdate,最近,我在我的4000多万行Postgres表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(); 我在两个事务中这样做,因为在一个新列上设置默认值会导致Postgres重
ALTER TABLE queries
ADD COLUMN ml_partition_source UUID;
然后在另一个事务中,我执行了
ALTER TABLE queries
ALTER COLUMN ml_partition_source
SET DEFAULT public.gen_random_uuid();
我在两个事务中这样做,因为在一个新列上设置默认值会导致Postgres重写整个表,这可能需要几个小时,在生产中是不可接受的
现在,我想为添加新列之前存在的所有查询回填此列,而不锁定表。一种方法是使用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;
并使用选择回填分区源执行该操作;。但最终还是把桌子锁上了
如何在不影响生产或对生产影响最小的情况下回填柱
编辑:我的一个想法是将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是表的主键
这样,您就可以进行一些更大的更新,每个更新针对不同的ID范围
为了避免膨胀和过度锁定,请在各自的事务中运行每个语句,并在语句之间的表上启动一个显式真空。哦,太棒了!如果表的主键是UUID,您是否预计会出现任何问题?不,应该可以。您也不必使用主键——任何可以用来高效创建合理块的列都可以。