1. 程式人生 > > PostgreSQL建立欄位設定預設值並且不鎖表

PostgreSQL建立欄位設定預設值並且不鎖表

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;