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;