这是一个实例,我要对一个数据库表的数据创建一个统计缓存,这个统计缓存由于数据量较大,我采用了按年分布表的方式。首先设计了基表,所有的数据分区都是基于这个基表继承而来。为了方便分区和维护,我专门写了一个函数来创建分区子表。
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)如果指定的触发器,则创建触发器,以便建立触发器与执行函数之间的关联。
具体的步骤就不在分析,看得懂的自然看明白了,看不懂了,还是该干嘛干嘛吧。
