引数1=処理年月 例 202202
内部パラメータ:
未来件数 = 何か月先まで作成するか? デフォルト 2
過去件数 = 何か月前まで保持するか? デフォルト 2
仕様:
格納対象年月 をパーティション名とし、パーティション作成、削除の判定は格納対象年月を使用する
古いパーティションデータは別テーブルに退避後削除する
(8.0.31)
-- テストテーブル作成
drop table tab1;
drop table tab2;
create table tab1
( col1 bigint not null
, col2 datetime not null
)
partition by RANGE COLUMNS (col2)
( partition p202201 values less than ('2022-02-01')
, partition p202202 values less than ('2022-03-01')
, partition p202203 values less than ('2022-04-01')
, partition p202204 values less than ('2022-05-01')
, partition pmax values less than (MAXVALUE)
);
create table tab2
( col1 bigint not null
, col2 datetime not null
)
partition by RANGE COLUMNS (col2)
( partition p202201 values less than ('2022-02-01')
, partition p202202 values less than ('2022-03-01')
, partition p202203 values less than ('2022-04-01')
, partition p202204 values less than ('2022-05-01')
, partition pmax values less than (MAXVALUE)
);
insert into tab1 values(10,'2022-01-20' );
insert into tab2 values(10,'2032-01-20' );
select table_name,partition_name,partition_description
from information_schema.partitions
where table_schema = 'test'
and table_name in ('tab1','tab2')
order by table_name,partition_name
;
select count(*) from tab1;
select count(*) from tab2;
select count(*) from tab1_taihi;
select count(*) from tab2_taihi;
-- メンテプロシージャ作成
drop procedure proc_partition_mainte;
delimiter //
create procedure proc_partition_mainte(in p_yyyymm varchar(6) )
begin
declare va1 varchar(4000);
declare va2 varchar(4000);
declare va3 varchar(4000);
declare va4 varchar(4000);
declare va5 varchar(4000);
declare wk1 numeric;
declare C_FUTURE_COUNT numeric default 2;
declare C_PAST_COUNT numeric default 2;
declare done integer;
declare cur1 cursor for select distinct table_name
from information_schema.partitions
where table_schema = 'test'
and REGEXP_LIKE(partition_name, 'p:digit:{6}')
order by table_name
;
declare continue handler for sqlstate '02000' set done = 1;
declare continue handler for sqlstate 'HY000' set done = 0;
-- 未来年月取得(パーティション名用)
set @q := concat('select DATE_ADD( concat(substr(''',p_yyyymm,''',1,4),''-'',substr(''',p_yyyymm,''',5,2),''-01''), INTERVAL ',C_FUTURE_COUNT,' MONTH) into @val');
prepare stmt from @q;
execute stmt;
deallocate prepare stmt;
set va1 = ( select replace(substr(@val,1,7),'-','') );
-- 未来年月日取得(パーティション境界用)
set @q := concat('select DATE_ADD( concat(substr(''',p_yyyymm,''',1,4),''-'',substr(''',p_yyyymm,''',5,2),''-01''), INTERVAL ',C_FUTURE_COUNT+1,' MONTH) into @val');
prepare stmt from @q;
execute stmt;
deallocate prepare stmt;
set va2 = @val;
-- 過去年月取得(パーティション名用)
set @q := concat('select DATE_ADD( concat(substr(''',p_yyyymm,''',1,4),''-'',substr(''',p_yyyymm,''',5,2),''-01''), INTERVAL ',-1*C_PAST_COUNT,' MONTH) into @val');
prepare stmt from @q;
execute stmt;
deallocate prepare stmt;
set va3 = ( select replace(substr(@val,1,7),'-','') );
set done = 0;
open cur1;
fetch cur1 into va4;
while done != 1 do
-- 退避テーブル名
set va5 = concat(va4,'_taihi');
-- 退避テーブル存在チェック
set wk1 = ( select count(*) from information_schema.tables where table_schema='test' and table_name = va5 );
-- 退避テーブル作成
if wk1 = 0 then
set @q = concat(' create table ',va5,' as select * from ',va4,' where 1=2 ' );
prepare stmt from @q;
execute stmt;
deallocate prepare stmt;
end if;
-- メンテ実行
set @q = concat('alter table ',va4);
set @q = concat(@q ,' reorganize partition pmax into ( ');
set @q = concat(@q ,' partition p',va1,' values less than (''',va2,''') ');
set @q = concat(@q ,' ,partition pmax values less than ( MAXVALUE ) )');
prepare stmt from @q;
execute stmt;
deallocate prepare stmt;
set @q = concat(' insert into ',va5,' select * from ',va4,' partition(p',va3,') ');
prepare stmt from @q;
execute stmt;
deallocate prepare stmt;
set @q = concat(' alter table ',va4,' drop partition p',va3,' ');
prepare stmt from @q;
execute stmt;
deallocate prepare stmt;
fetch cur1 into va4;
end while;
close cur1;
end
//
delimiter ;
-- 動作確認
call proc_partition_mainte('202203');
call proc_partition_mainte('202204');
call proc_partition_mainte('202205');
select table_name,partition_name,partition_description
from information_schema.partitions
where table_schema = 'test'
and table_name in ('tab1','tab2')
order by table_name,partition_name
;
select count(*) from tab1;
select count(*) from tab2;
select count(*) from tab1_taihi;
select count(*) from tab2_taihi;
(19c)
-- テストテーブル作成
drop table tab1 purge;
drop table tab2 purge;
create table tab1
( col1 int not null
, col2 timestamp not null
)
partition by range (col2)
( partition p202201 values less than (to_date('20220201','yyyymmdd') )
, partition p202202 values less than (to_date('20220301','yyyymmdd') )
, partition p202203 values less than (to_date('20220401','yyyymmdd') )
, partition p202204 values less than (to_date('20220501','yyyymmdd') )
, partition pmax values less than (MAXVALUE)
);
create table tab2
( col1 int not null
, col2 timestamp not null
)
partition by range (col2)
( partition p202201 values less than (to_date('20220201','yyyymmdd') )
, partition p202202 values less than (to_date('20220301','yyyymmdd') )
, partition p202203 values less than (to_date('20220401','yyyymmdd') )
, partition p202204 values less than (to_date('20220501','yyyymmdd') )
, partition pmax values less than (MAXVALUE)
);
insert into tab1 values(10,to_date('20220120','yyyymmdd') );
insert into tab2 values(10,to_date('20320120','yyyymmdd') );
commit;
select table_name,partition_name,high_value
from user_tab_partitions
where table_name in ('TAB1','TAB2')
order by table_name,partition_name
;
select count(*) from tab1;
select count(*) from tab2;
select count(*) from tab1_taihi;
select count(*) from tab2_taihi;
-- メンテプロシージャ作成
set serveroutput on
create or replace procedure proc_partition_mainte(p_yyyymm in varchar2)
authid current_user
as
cursor cur1 is select distinct table_name
from user_tab_partitions
where REGEXP_LIKE(partition_name, 'P\d{6}')
order by table_name;
va1 varchar2(4000);
va2 varchar2(4000);
va3 varchar2(4000);
va4 varchar2(4000);
wk1 number;
C_FUTURE_COUNT number := 2;
C_PAST_COUNT number := 2;
vsql varchar2(4000);
begin
-- 未来年月取得(パーティション名用)
select to_char(add_months(to_date(p_yyyymm||'01'),C_FUTURE_COUNT) ,'YYYYMM') into va1 from dual;
-- 未来年月日取得(パーティション境界用)
select to_char(add_months(to_date(p_yyyymm||'01'),C_FUTURE_COUNT+1) ,'YYYYMMDD') into va2 from dual;
-- 過去年月取得(パーティション名用)
select to_char(add_months(to_date(p_yyyymm||'01'),-1*C_PAST_COUNT) ,'YYYYMM') into va3 from dual;
for c1 in cur1 loop
-- 退避テーブル名
va4 := c1.table_name||'_TAIHI';
-- 退避テーブル存在チェック
select count(*) into wk1 from user_tables where table_name = va4;
-- 退避テーブル作成
if wk1 = 0 then
vsql := 'create table '||va4||' as select * from '||c1.table_name||' where 1=2 ';
execute immediate vsql;
end if;
-- メンテ実行
vsql := '';
vsql := vsql || ' alter table '|| c1.table_name;
vsql := vsql || ' split partition pmax at (to_date('''||va2||''',''yyyymmdd'') ) ';
vsql := vsql || ' into ( partition p'||va1||', partition pmax) ';
vsql := vsql || ' update indexes ';
begin
execute immediate vsql;
exception when others then
null;
end;
vsql := ' insert into '||va4||' select * from '||c1.table_name||' partition(p'||va3||') ';
begin
execute immediate vsql;
exception when others then
null;
end;
vsql := ' alter table '||c1.table_name||' drop partition p'||va3||' update indexes ';
begin
execute immediate vsql;
exception when others then
null;
end;
end loop;
end;
/
sho error
-- 動作確認
exec proc_partition_mainte('202203');
exec proc_partition_mainte('202204');
exec proc_partition_mainte('202205');
select table_name,partition_name,high_value
from user_tab_partitions
where table_name in ('TAB1','TAB2')
order by table_name,partition_name
;
select count(*) from tab1;
select count(*) from tab2;
select count(*) from tab1_taihi;
select count(*) from tab2_taihi;
(15)
-- テストテーブル作成
drop table tab1;
drop table tab2;
create table tab1
( col1 bigint not null
, col2 timestamp not null
)
partition by range ( col2 )
;
create table tab1p202201 partition of tab1 for values from (MINVALUE) to ('2022-02-01');
create table tab1p202202 partition of tab1 for values from ('2022-02-01') to ('2022-03-01');
create table tab1p202203 partition of tab1 for values from ('2022-03-01') to ('2022-04-01');
create table tab1p202204 partition of tab1 for values from ('2022-04-01') to ('2022-05-01');
create table tab1pmax partition of tab1 for values from ('2022-05-01') to (MAXVALUE);
create table tab2
( col1 bigint not null
, col2 timestamp not null
)
partition by range ( col2 )
;
create table tab2p202201 partition of tab2 for values from (MINVALUE) to ('2022-02-01');
create table tab2p202202 partition of tab2 for values from ('2022-02-01') to ('2022-03-01');
create table tab2p202203 partition of tab2 for values from ('2022-03-01') to ('2022-04-01');
create table tab2p202204 partition of tab2 for values from ('2022-04-01') to ('2022-05-01');
create table tab2pmax partition of tab2 for values from ('2022-05-01') to (MAXVALUE);
insert into tab1 values(10,'2022-01-20' );
insert into tab2 values(10,'2032-01-20' );
\d+ tab1
\d+ tab2
select count(*) from tab1;
select count(*) from tab2;
select count(*) from tab1_taihi;
select count(*) from tab2_taihi;
-- メンテプロシージャ作成
drop procedure proc_partition_mainte;
create or replace procedure proc_partition_mainte(
p_yyyymm in varchar
)
language plpgsql
as $$
declare
cur1 cursor for select distinct t1.tablename
from pg_tables t1
where t1.schemaname = 'public'
and exists ( select 1 from pg_class t2
where t2.relkind = 'p'
and t2.relnamespace = t1.schemaname::regnamespace
and t2.relname = t1.tablename )
and exists ( select REGEXP_MATCHES(t3.tablename , '^'||t1.tablename||'p[0-9]{6}') from pg_tables t3
where t1.schemaname = t3.schemaname )
order by t1.tablename;
va1 varchar(4000);
va2 varchar(4000);
va3 varchar(4000);
va4 varchar(4000);
va5 varchar(4000);
wk1 numeric;
C_FUTURE_COUNT numeric := 2;
C_PAST_COUNT numeric := 2;
vsql varchar(4000);
begin
-- 未来年月取得(パーティション名用)
vsql := 'select to_char( ('''||p_yyyymm||'''||''01'')::date + interval '''||C_FUTURE_COUNT||' month'',''YYYYMM'') ';
execute vsql into va1;
-- 未来年月日取得(パーティション境界用)
vsql := 'select to_char( ('''||p_yyyymm||'''||''01'')::date + interval '''||C_FUTURE_COUNT||' month'',''YYYY-MM-DD'') ';
execute vsql into va2;
vsql := 'select to_char( ('''||p_yyyymm||'''||''01'')::date + interval '''||C_FUTURE_COUNT+1||' month'',''YYYY-MM-DD'') ';
execute vsql into va3;
-- 過去年月取得(パーティション名用)
vsql := 'select to_char( ('''||p_yyyymm||'''||''01'')::date + interval '''|| (-1)*C_PAST_COUNT||' month'',''YYYYMM'') ';
execute vsql into va4;
for c1 in cur1 loop
-- 退避テーブル名
va5 := c1.tablename||'_taihi';
-- 退避テーブル存在チェック
select count(*) strict into wk1 from pg_tables where schemaname = 'public' and tablename = va5;
-- 退避テーブル作成
if wk1 = 0 then
vsql := ' create table '||va5||' ( like '|| c1.tablename ||' )';
execute vsql ;
end if;
-- メンテ実行
begin
vsql := ' alter table '||c1.tablename||' detach partition '||c1.tablename||'pmax ';
execute vsql;
vsql := ' alter table '||c1.tablename||'pmax rename to '||c1.tablename||'pmax_old ';
execute vsql;
vsql := ' create table '||c1.tablename||'p'||va1||' partition of '||c1.tablename||' for values from ('''||va2||''') to ('''||va3||''') ';
execute vsql;
vsql := ' create table '||c1.tablename||'pmax partition of '||c1.tablename||' for values from ('''||va3||''') to (MAXVALUE) ';
execute vsql;
vsql := ' insert into '||c1.tablename||' select * from '||c1.tablename||'pmax_old ';
execute vsql;
vsql := ' drop table '||c1.tablename||'pmax_old ';
execute vsql;
vsql := ' alter table '||c1.tablename||' detach partition '||c1.tablename||'p'||va4;
execute vsql;
vsql := ' insert into '||va5||' select * from '||c1.tablename||'p'||va4;
execute vsql;
vsql := ' drop table '||c1.tablename||'p'||va4;
execute vsql;
exception when others then
null;
end;
end loop;
end;
$$;
-- 動作確認
call proc_partition_mainte('202203');
call proc_partition_mainte('202204');
call proc_partition_mainte('202205');
\d+ tab1
\d+ tab2
select count(*) from tab1;
select count(*) from tab2;
select count(*) from tab1_taihi;
select count(*) from tab2_taihi;
(2019)
-- テストテーブル作成
drop table tab1;
drop table tab2;
drop partition scheme ps1;
drop partition function pf1;
create partition function pf1(datetime2) as range right
for values ('2022-02-01','2022-03-01','2022-04-01','2022-05-01');
create partition scheme ps1 as partition pf1 all to ([PRIMARY]);
create table tab1
( col1 bigint not null
, col2 datetime2 not null
) on ps1(col2)
;
create table tab2
( col1 bigint not null
, col2 datetime2 not null
) on ps1(col2)
;
insert into tab1 values(10,'2022-01-20' );
insert into tab2 values(10,'2032-01-20' );
select distinct object_name(i.object_id) table_name ,
pf.name partitionfunction,
ps.name partitionscheme,
rv.value range_value
from sys.indexes i
inner join sys.partition_schemes ps on ps.data_space_id = i.data_space_id
inner join sys.partition_functions pf on pf.function_id = ps.function_id
inner join sys.partition_range_values rv on pf.function_id = rv.function_id
where object_name(i.object_id) in ('tab1','tab2')
order by table_name, range_value;
select count(*) from tab1;
select count(*) from tab2;
select count(*) from tab1_taihi;
select count(*) from tab2_taihi;
-- メンテプロシージャ作成
create or alter procedure proc_partition_mainte(
@p_yyyymm varchar(4000)
)
as
begin
set nocount on;
declare @va1 varchar(4000);
declare @va2 varchar(4000);
declare @va3 varchar(4000);
declare @va4 varchar(4000);
declare @va5 varchar(4000);
declare @wk1 numeric;
declare @C_FUTURE_COUNT numeric = 2;
declare @C_PAST_COUNT numeric = 2;
declare @vsql nvarchar(4000);
-- 未来年月日取得(パーティション境界用)
set @va1 = (select format(dateadd(month, @C_FUTURE_COUNT+1,cast(@p_yyyymm+'01' as datetime2) ),'yyyy-MM-dd') )
-- 過去年月日取得(パーティション境界用)
set @va2 = (select format(dateadd(month, (-1)*@C_PAST_COUNT+1,cast(@p_yyyymm+'01' as datetime2) ),'yyyy-MM-dd') )
declare cur1 cursor for select distinct object_name(i.object_id) table_name
from sys.indexes i
inner join sys.partition_schemes ps on ps.data_space_id = i.data_space_id
inner join sys.partition_functions pf on pf.function_id = ps.function_id
where pf.name = 'pf1'
order by table_name;
open cur1;
fetch next from cur1 into @va3;
while @@fetch_status = 0
begin
-- 退避テーブル名
set @va4 = concat(@va3,'_taihi');
-- 退避テーブル存在チェック
set @wk1 = ( select count(*) from sys.tables where name = @va4 );
-- 退避テーブル作成
if @wk1 = 0
begin
set @vsql = N' select * into '+@va4+' from '+@va3+' where 1=2 ';
execute (@vsql);
end;
-- パーティションキー取得
set @vsql = N' select @va5 = c.name ';
set @vsql = @vsql + N' from sys.tables t ';
set @vsql = @vsql + N' join sys.indexes i ';
set @vsql = @vsql + N' on t.object_id = i.object_id ';
set @vsql = @vsql + N' and i.type <= 1 ';
set @vsql = @vsql + N' join sys.partition_schemes ps ';
set @vsql = @vsql + N' on ps.data_space_id = i.data_space_id ';
set @vsql = @vsql + N' join sys.index_columns ic ';
set @vsql = @vsql + N' on ic.object_id = i.object_id ';
set @vsql = @vsql + N' and ic.index_id = i.index_id ';
set @vsql = @vsql + N' and ic.partition_ordinal >= 1 ';
set @vsql = @vsql + N' join sys.columns c ';
set @vsql = @vsql + N' on ic.object_id = c.object_id ';
set @vsql = @vsql + N' and ic.column_id = c.column_id ';
set @vsql = @vsql + N' where t.name = '''+@va3+''' ';
execute sp_executesql
@vsql, N'@va5 varchar(4000) OUT', @va5 OUT;
-- メンテ実行(データ退避)
begin try
set @vsql = N' insert into '+@va4+' select * from '+@va3+' where '+@va5+' < '''+@va2+''' ';
execute (@vsql);
set @vsql = N' delete from '+@va3+' where '+@va5+' < '''+@va2+''' ';
execute (@vsql);
end try
begin catch
end catch
fetch next from cur1 into @va3;
end
close cur1;
deallocate cur1;
-- メンテ実行(パーティション分割マージ)
begin try
set @vsql = N' alter partition scheme ps1 next used [PRIMARY] ';
execute (@vsql);
set @vsql = N' alter partition function pf1() split range('''+@va1+''') ';
execute (@vsql);
set @vsql = N' alter partition function pf1() merge range('''+@va2+''') ';
execute (@vsql);
end try
begin catch
end catch
end
go
-- 動作確認
exec proc_partition_mainte '202203';
exec proc_partition_mainte '202204';
exec proc_partition_mainte '202205';
select distinct object_name(i.object_id) table_name ,
pf.name partitionfunction,
ps.name partitionscheme,
rv.value range_value
from sys.indexes i
inner join sys.partition_schemes ps on ps.data_space_id = i.data_space_id
inner join sys.partition_functions pf on pf.function_id = ps.function_id
inner join sys.partition_range_values rv on pf.function_id = rv.function_id
where object_name(i.object_id) in ('tab1','tab2')
order by table_name, range_value;
select count(*) from tab1;
select count(*) from tab2;
select count(*) from tab1_taihi;
select count(*) from tab2_taihi;