1创建测试表
drop table if exists test009;
create table test009(
objectid bigint not null,
name text not null,
--flag integer default(2) not null, --用于演示添加的字段
constraint pk_test009_objectid primary key (objectid) with (fillfactor=100)
) with (fillfactor=100);
2 插入测试数据1000W
drop function if exists gen_random(int,int);
create or replace function gen_random(int,int)
returns text
as $$
select string_agg(((random()*(9-0)+0 )::integer)::text , '') from generate_series(1,(random()*($2-$1)+$1)::integer);
$$ language sql;
do $$
declare
v_dys integer[];
begin
for i in 1..1000 loop
insert into test009
select (id + (i-1)*10000),gen_random(8,32) from generate_series(1,10000) as id;
raise notice '%', i;
end loop;
end;
$$;
analyze verbose test009;
select count(*) from test009;
3 直接添加字段并设置默认值会锁表
设置默认值后实际上也是更新了数据
select ctid from test009 order by objectid limit 100;
alter table test009
add column flag integer default(2) not null;
--注意这个表太小,修改完成后被autovacuum立即处理了,测试前先关闭autovacuum或使用大表
select ctid from test009 order by objectid limit 100;
alter table test009
drop column flag;
完成以后也要vacuum,vacuum会锁表.或者等待autovacuum处理
4 先添加字段但不设置默认值
alter table test009
add column flag integer;
然后更新flag为默认值
do $$
declare
v_currentid bigint;
v_rec record;
begin
v_currentid := -1;
loop
for v_rec in (with cte as(
select objectid from test009 where objectid>v_currentid order by objectid limit 1000
)select array_agg(objectid) as ids from cte) loop
update test009 set flag=2 where objectid=any(v_rec.ids);
v_currentid := v_rec.ids[1000];
end loop;
--raise notice '%', v_currentid;
if( v_currentid is null ) then
return;
end if;
end loop;
end;
$$;
--在执行过程中在另一过程执行可以查出数据,只是较慢
select count(*) from test009;
4 最后一步
--设置为not null
alter table test009
alter column flag set not null;
--因为更新了大量的数据,所以需要vacuum一下表
--注意 alter table test009 add column flag integer default(2) not null;也更新了表,完成以后也要vacuum
vacuum freeze verbose analyze test009;