PostgreSQL创建分区编写过程小结

这是一个实例,我要对一个数据库表的数据创建一个统计缓存,这个统计缓存由于数据量较大,我采用了按年分布表的方式。首先设计了基表,所有的数据分区都是基于这个基表继承而来。为了方便分区和维护,我专门写了一个函数来创建分区子表。

create or replace function stat_partition(stat_year integer)
returns void
as
$BODY$
declare 
   sql character varying;
   tablename character varying;
   tblyear character varying;
   i integer;
   cur cursor for select p.relname from pg_inherits i,pg_class p where i.inhparent=(select oid from pg_class where relname='base_stat') and p.oid=i.inhrelid order by p.relname;
begin
tablename='stat_'||cast(stat_year as character varying);
--创建表
sql='create table '||tablename||
  ' (constraint pk_'||tablename||' primary key (id),'||
  ' constraint chk_'||tablename||' check ((from_date>='''||cast(stat_year as character varying)||'-1-1''::date) and (to_date<='''||cast(stat_year+1 as character varying)||'-1-1''::date)))'||
  ' inherits (base_stat);';
execute sql;
--表注释
sql='comment on table '||tablename|| ' is '''||cast(stat_year as character varying)||' 年统计结果汇总缓存表'';';
execute sql;
-- 表索引
-- areacode
sql='create index idx_'||tablename||'_areacode on '||tablename||' (areacode);';
execute sql;
-- from_age
sql='create index idx_'||tablename||'_from_age on '||tablename||' (from_age);';
execute sql;
-- to_age
sql='create index idx_'||tablename||'_to_age on '||tablename||' (to_age);';
execute sql;
-- from_date
sql='create index idx_'||tablename||'_from_date on '||tablename||' (from_date);';
execute sql;
-- to_date
sql='create index idx_'||tablename||'_to_date on '||tablename||' (to_date);';
execute sql;
-- illcode
sql='create index idx_'||tablename||'_to_illcode on '||tablename||' (illcode);';
execute sql;
-- 创建触发器函数
sql='create or replace function tgr_base_stat() returns trigger as $$ '||chr(10)||'begin'||chr(10);
open cur;
fetch cur into tablename;
i=0;
while found loop
  tblyear=right(tablename,4);
  if i=0 then
    sql=sql||'if New.from_date>='''||tblyear||'-1-1'' and New.to_date<='''||cast(cast(tblyear as integer)+1 as character varying)||'-1-1'' then '||chr(10)||
	'insert into '||tablename||' values (New.*);'||chr(10);
  else
    sql=sql||'elsif New.from_date>='''||tblyear||'-1-1'' and New.to_date<='''||cast(cast(tblyear as integer)+1 as character varying)||'-1-1'' then '||chr(10)||
	'insert into '||tablename||' values (New.*);'||chr(10);
  end if;
  i=i+1;
  fetch cur into tablename;
end loop;
close cur;
sql=sql||'else '||chr(10)||' raise exception ''指定的记录无法自动插入任何一个分区,请检查数据或调用stat_partition(%)建立新的分区。'',extract(year from New.from_date);'
  ||chr(10)||'end if;'||chr(10)||'return NULL;'||chr(10)|| 'end; $$ language plpgsql;';  
execute sql;  
if not exists (select * from pg_trigger where tgname='stat_insert_redirect') then
  begin
  sql='create trigger stat_insert_redirect before insert on base_stat for each row execute procedure tgr_base_stat();';
  execute sql; 
  end;
 end if;
end; 
$BODY$ language plpgsql;

函数主要做了以下事情:

(1)用 create or replace 而不是 create 方便在函数已经存在的时候,直接替换,这就相比MSSQL方便多了。

(2)声明了一个游标来获取从base_stat表继承下来的所有子表,以便自动更新触发器触发时要执行的函数。

(3)首先从父表继承创建了子表,并自动创建了主键和检查约束,以便进行数据分区。

(4)接下来是为表加入注释,并且自动添加需要的索引。

(5)更新触发器函数,以便在插入数据时自动进入新的分区。

(6)如果指定的触发器,则创建触发器,以便建立触发器与执行函数之间的关联。

具体的步骤就不在分析,看得懂的自然看明白了,看不懂了,还是该干嘛干嘛吧。

分享到: