oracle分区表自动维护

前几天因为工作需要,所以在网上查到分区表自动维护资料。

http://blog.csdn.net/rulev5/article/details/8505955中找到了对于时间分区表的自动维护脚本,但是工作需要对时间和字符分区都进行维护,于是对脚本进行了改进。

本脚本主要由2个部分组成:sys_ConfigTable.sql、sys_pro_AddAndDropPartition.sql
1、sys_ConfigTable.sql 主要创建了一张配置表:这里填写具体要自动维护的表名、保存天数、每天分区的个数等等;

2、sys_pro_AddAndDropPartition.sql 这个用来自动增加表分区,删除过期分区;

3、sys_pr_mergetableandrebuildindex.sql这个用户重建配置表中的表的失效的全局索引


1、sys_ConfigTable.sql

CREATE TABLE TB_PARTITION_CONFIGTABLE
(
  NAME    VARCHAR2(64 BYTE)                     NOT NULL,
  VALUE   VARCHAR2(64 BYTE)                     NOT NULL,
  TYPE    VARCHAR2(64 BYTE)                     NOT NULL,
  ISRUN   NUMBER(1)                             NOT NULL,
  REMARK  VARCHAR2(64 BYTE)
);

COMMENT ON TABLE TB_PARTITION_CONFIGTABLE IS '分区自动维护配置表';

COMMENT ON COLUMN TB_PARTITION_CONFIGTABLE.NAME IS '表名';

COMMENT ON COLUMN TB_PARTITION_CONFIGTABLE.VALUE IS '值';

COMMENT ON COLUMN TB_PARTITION_CONFIGTABLE.TYPE IS 'protocal:日志表,save:保存,num_part_byday:添加分区,category:分区类别';

COMMENT ON COLUMN TB_PARTITION_CONFIGTABLE.ISRUN IS '1:使用,0:不使用';

COMMENT ON COLUMN TB_PARTITION_CONFIGTABLE.REMARK IS '备注';

Insert into TB_PARTITION_CONFIGTABLE
   (NAME, VALUE, TYPE, ISRUN, REMARK)
 Values
   ('TL_IF_LOG', 'TL_IF_LOG', 'protocal', 1, '接口日志表');
Insert into TB_PARTITION_CONFIGTABLE
   (NAME, VALUE, TYPE, ISRUN, REMARK)
 Values
   ('TL_IF_LOG', '7', 'save', 1, '日志保存天数');
Insert into TB_PARTITION_CONFIGTABLE
   (NAME, VALUE, TYPE, ISRUN, REMARK)
 Values
   ('TL_IF_LOG', '1', 'num_part_byday', 1, '每天要添加的分区个数');
Insert into TB_PARTITION_CONFIGTABLE
   (NAME, VALUE, TYPE, ISRUN, REMARK)
 Values
   ('TL_IF_LOG', 'date', 'category', 1, '时间分区');

Insert into TB_PARTITION_CONFIGTABLE
   (NAME, VALUE, TYPE, ISRUN, REMARK)
 Values
   ('TL_ITV_DATA_LOG', 'TL_ITV_DATA_LOG', 'protocal', 1, 'PV日志表');
Insert into TB_PARTITION_CONFIGTABLE
   (NAME, VALUE, TYPE, ISRUN, REMARK)
 Values
   ('TL_ITV_DATA_LOG', '30', 'save', 1, '日志保存天数');
Insert into TB_PARTITION_CONFIGTABLE
   (NAME, VALUE, TYPE, ISRUN, REMARK)
 Values
   ('TL_ITV_DATA_LOG', '1', 'num_part_byday', 1, '每天要添加的分区个数');
Insert into TB_PARTITION_CONFIGTABLE
   (NAME, VALUE, TYPE, ISRUN, REMARK)
 Values
   ('TL_ITV_DATA_LOG', 'char', 'category', 1, '字符分区');

   2、sys_pro_AddAndDropPartition.sql

 
 CREATE OR REPLACE PROCEDURE PR_AddAndDropPartition AS  
  /*******************************************************  
  功能:添加分区表的指定分区  
  示例: exec sys_pro_AddAndDropPartition;  
  说明:协议、表名称、保存天数从配置表TB_PARTITION_CONFIGTABLE读取  
  ********************************************************/  
  v_sql_gettablename       long; --取协议对于的表名sql  
  v_sql_gettablespacename  long; --取表对应的表空间sql  
  v_tablename              dbms_sql.Varchar2_Table; --协议对于的表名  
  v_tableSpaceName         varchar2(32); --表对应的表空间  
  v_sql_get_partition_name long;  
  v_del_partition_name     dbms_sql.Varchar2_Table;  
  v_SqlExec                VARCHAR2(2000); --DDL语句变量  
  v_SqlDel                 VARCHAR2(2000); --删除表分区  
  v_Partwareid1            NUMBER; --创建分区的wareid
  v_Partwareid2            VARCHAR2(20); --创建分区的字符
  v_err_num                NUMBER; --ORA错误号  
  v_err_msg                VARCHAR2(100); --错误描述  
  partNum                  NUMBER; --添加分区的个数  
  interval_day             NUMBER;  
  v_sql_getday             long;  
  v_saveday                varchar2(32);  
  v_part_wareid_nim        NUMBER; --v_tablename 表分区的最小wareid号  
  v_part_wareid_max        NUMBER; --v_tablename 表分区的最大wareid号  
  v_begin                  NUMBER; ----字符串的开始位置  
  v_end                    NUMBER; --字符串结束的位置   
  v_part_name              VARCHAR2(100); --要添加分区表的名称的前缀  
  num_part_byday           int;--每天要添加的分区个数,从TB_PARTITION_TB_PARTITION_CONFIGTABLE中读取
  partType           varchar2(5);--分区类型(是字符串分区还是时间分区),从TB_PARTITION_TB_PARTITION_CONFIGTABLE中读取
  v_num_part_byday         int;  
BEGIN  
  --最外层,对每个协议循环  
  v_sql_gettablename := 'select value from TB_PARTITION_CONFIGTABLE where type=''protocal'' and isrun=1';  
  execute immediate v_sql_gettablename bulk collect  
    into v_tablename;  
  for k in 1 .. v_tablename.count loop  
    v_sql_gettablespacename := 'select distinct TABLESPACE_NAME  from user_tab_partitions  where table_name = ''' ||  
                               v_tablename(k) || '''';  
    dbms_output.put_line(v_sql_gettablespacename);  
    execute immediate v_sql_gettablespacename  
      into v_tableSpaceName;  
    dbms_output.put_line('表空间为' || v_tableSpaceName);  
 
    --字符串的开始位置  
    select INSTR(partition_name, '_', 1, 1) + 1  
      into v_begin  
      from user_tab_partitions  
     where table_name = UPPER(v_tablename(k))  
       and rownum < 2;  
    dbms_output.put_line('字符串的开始位置 ' || v_begin);   
    --查询分区表tablename的最大wareid值,SUBSTR(partition_name, v_begin, v_count)表示分区名后面的分区数  
    select max(to_number(SUBSTR(partition_name, v_begin)))  
      into v_part_wareid_max  
      from user_tab_partitions  
     WHERE table_name = UPPER(v_tablename(k));  
    dbms_output.put_line('最大分区名称' || v_part_wareid_max);  
    --查询分区表tablename的最小wareid值,删除分区使用  
    select min(to_number(SUBSTR(partition_name, v_begin)))  
      into v_part_wareid_nim  
      from user_tab_partitions  
     WHERE table_name = UPPER(v_tablename(k));  
    dbms_output.put_line('最小分区名称' || v_part_wareid_nim);  
    --计算分区表的名称  
    select SUBSTR(partition_name, 1, v_begin - 1)  
      into v_part_name  
      from user_tab_partitions  
     WHERE table_name = UPPER(v_tablename(k))  
       and rownum < 2;  
    dbms_output.put_line('分区开头为' || v_part_name);  
    v_Partwareid1 := v_part_wareid_max;  
  dbms_output.put_line('最大分区为' || v_Partwareid1 );  
    partNum       := (trunc(sysdate) - to_date(v_part_wareid_max,'yyyymmdd')) + 1;  
    dbms_output.put_line('应该新建' || partNum || '天的数据');  
    --如果表未建好,执行建表语句  
  if partNum > 0 then  
      --新加分区表  
      FOR i IN 1 .. partNum LOOP  
        dbms_output.put_line('v_Partwareid1:' || v_Partwareid1);  
        select to_number(to_char((to_date(v_Partwareid1, 'yyyymmdd') + 1),  
                                 'yyyymmdd'))  
          into v_Partwareid1  
          from dual;  
        dbms_output.put_line(v_Partwareid1); --20111125  
        select b.value into num_part_byday from TB_PARTITION_CONFIGTABLE a, TB_PARTITION_CONFIGTABLE b where a.name = b.name and b.type = 'num_part_byday'  
           and a.value = UPPER(v_tablename(k)) and a.type = 'protocal' and a.isrun = 1;  
    
    select b.value into partType from TB_PARTITION_CONFIGTABLE a, TB_PARTITION_CONFIGTABLE b where a.name = b.name and b.type = 'category'  
           and a.value = UPPER(v_tablename(k)) and a.type = 'protocal' and a.isrun = 1;  
        if num_part_byday=0 or num_part_byday is null  then  
           num_part_byday:=1;  
        end if;  
        v_num_part_byday:=0;  
        loop   
          v_num_part_byday := v_num_part_byday + 24/num_part_byday;  

    if partType='date' then  
           v_SqlExec := 'ALTER TABLE ' || v_tablename(k) ||  
                       ' ADD PARTITION ' || v_part_name || v_Partwareid1 ||   
                       ' values less than(to_date( ''' ||    
                        v_Partwareid1 ||
                       '235959'',''YYYYMMDDhh24miss'')) ';
        elsif partType='char' then
        select to_char(to_date(v_Partwareid1, 'yyyymmdd'),  
                                 'yyyy-mm-dd')  
          into v_Partwareid2  
          from dual;
            v_SqlExec := 'ALTER TABLE ' || v_tablename(k) ||  
                       ' ADD PARTITION ' || v_part_name || v_Partwareid1 ||   
                       ' values less than( ''' ||    
                        v_Partwareid2 ||
                       ''' ) ';

        end if;     
                    dbms_output.put_line('创建表分区' || i || '=' || v_SqlExec);  
                    dbms_output.put_line(v_SqlExec);  
          DBMS_Utility.Exec_DDL_Statement(v_SqlExec);  
          exit when v_num_part_byday >= 24;  
        end loop;  
      END LOOP;  
    end if;  
    --删除过期的分区表  
 
    --查询分区表tablename的最大wareid值,SUBSTR(partition_name, v_begin, v_count)表示分区名后面的分区数  
    select max(to_number(SUBSTR(partition_name, v_begin)))  
      into v_part_wareid_max  
      from user_tab_partitions  
     WHERE table_name = UPPER(v_tablename(k));  
    dbms_output.put_line('最大分区名称' || v_part_wareid_max);  
    --查询分区表tablename的最小wareid值,删除分区使用  
    select min(to_number(SUBSTR(partition_name, v_begin)))  
      into v_part_wareid_nim  
      from user_tab_partitions  
     WHERE table_name = UPPER(v_tablename(k));  
    dbms_output.put_line('最小分区名称' || v_part_wareid_nim);  
    select (to_date(v_part_wareid_max, 'YYYYMMDD') -  
           to_date(v_part_wareid_nim, 'YYYYMMDD'))  
      into interval_day  
      from dual;  
    dbms_output.put_line('已经创建分区天数为' || interval_day);  
    select b.value  
      into v_saveday  
      from TB_PARTITION_CONFIGTABLE a, TB_PARTITION_CONFIGTABLE b  
     where a.name = b.name  
       and b.type = 'save'  
       and a.value = v_tablename(k);  
    dbms_output.put_line('数据保存天数为' || v_saveday);  
    if interval_day > v_saveday then  
      for j in 1 .. (interval_day - v_saveday) loop  
        v_sql_get_partition_name := 'select partition_name from user_tab_partitions where table_name= ''' ||  
                                    v_tablename(k) ||  
                                    ''' and partition_name like ''%' ||  
                                    v_part_wareid_nim || '%''';  
        --        execute immediate v_sql_get_partition_name bulk collect  
        --          into v_del_partition_name;  
        dbms_output.put_line(v_sql_get_partition_name);  
        execute immediate v_sql_get_partition_name bulk collect  
          into v_del_partition_name;  
        for l in 1 .. v_del_partition_name.count loop  
          v_SqlDel := 'ALTER TABLE ' || v_tablename(k) ||  
                      ' DROP PARTITION ' || v_del_partition_name(l);  
          dbms_output.put_line(v_SqlDel);  
          execute immediate (v_SqlDel);  
        end loop;  
        v_part_wareid_nim := v_part_wareid_nim + 1;  
        dbms_output.put_line('已删除' || v_part_wareid_nim);  
      end loop;  
    end if;  
  end loop;  
  commit;
  /*  EXCEPTION  
  WHEN OTHERS THEN  
      v_err_num := SQLCODE;  
      v_err_msg := SUBSTR(SQLERRM, 1, 100);  
      dbms_output.put_line('pro_ADD_PARTITION_wareid执行出现异常,错误码=' ||  
                           v_err_num || '错误描述=' || v_err_msg);  
  commit;*/  
END PR_AddAndDropPartition;
/

   3、sys_pr_mergetableandrebuildindex.sql

CREATE OR REPLACE procedure OPENAPI.PR_MERGETABLEANDREBUILDINDEX is  
  --数据文件合并在表空间的名称  
  /*******************************************************  
  功能:合并分区表  
  示例: exec PR_MERGETABLEANDREBUILDINDEX;  
  表空间、表通过TB_PARTITION_CONFIGTABLE读取配置  
  ********************************************************/     
  v_SqlInd          long; --查找失效的索引sql  
  v_Ind             dbms_sql.Varchar2_Table; --存放失效的索引  
  v_SqlInd2         long; --重建索引sql    
  --新增部分  
  v_protocal         varchar2(32);  
  v_sql_gettablename long;  
  v_tablename        dbms_sql.Varchar2_Table;   
begin  
  --最外层循环,根据协议取出表和表空间  
  --取出表  
    v_sql_gettablename := 'select value from TB_PARTITION_CONFIGTABLE where type=''protocal'' and isrun=1';  
  execute immediate v_sql_gettablename bulk collect  
    into v_tablename;  
      for l in 1 .. v_tablename.count loop  
    --取出表空间      
    --第二个内层循环重建失效的索引   
    --查询出失效的索引  
    select NAME into v_protocal from TB_PARTITION_CONFIGTABLE where TYPE='protocal' and VALUE=v_tablename(l);  
    v_SqlInd := 'select distinct index_name  
      from user_indexes  
     where  status = ''UNUSABLE'' and table_name = ''' ||  v_protocal || '''';  
    dbms_output.put_line(v_SqlInd);  
    --把失效索引名称赋值给v_Ind  
    execute immediate v_SqlInd bulk collect  
      into v_Ind;    
    dbms_output.put_line(v_Ind.count);
    --把全局索引重建  
    for k in 1 .. v_Ind.count loop  
      v_SqlInd2 := 'alter index ' || v_Ind(k) || ' rebuild ';  
      dbms_output.put_line(v_SqlInd2);  
       execute immediate v_SqlInd2;  
    end loop;  
  end loop;  
end;
/





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值