PostgreSQL建立欄位設定預設值並且不鎖表
阿新 • • 發佈:2018-11-10
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;