0

我创建了一个间隔分区表interval ( NUMTODSINTERVAL(1,'day') )

随着每天将事务数据记录到此表中,oracle 会自动创建每日分区。

需要每天截断前一天的分区,而不影响当天的分区。

由于删除会产生碎片,我被要求使用截断或删除。

4

1 回答 1

1

欢迎来到 SO!

请参阅下面的基本示例,该示例根据您传递的日期从间隔分区表中截断/删除前面的分区。
注意:您可能需要进一步微调它以适应基于特定数据加载行为和要求的各种场景和边缘情况。

为了说明,我正在创建一个带有间隔分区的示例表,如下所示......

create table testpart
(  value_date date  )
partition by range ( value_date )
interval ( NUMTODSINTERVAL(1,'day') )
( partition p1 values less than ( date '2020-01-01' ));

检查新创建的表上的默认分区..

select table_name, partition_name, interval from dba_tab_partitions where table_name = 'TESTPART';

|TABLE_NAME  |PARTITION_NAME    |INTERVAL |
|TESTPART    |P1                |NO       |  

插入数据当前日期(例如 4 月 16 日)和前一个日期(4 月 15 日)..

insert into testpart select date '2020-04-15' from dual;
insert into testpart select date '2020-04-16' from dual;
commit;

检查插入的数据..

select * from testpart;

| VALUE_DATE |
| 4/15/2020  |
| 4/16/2020  |

检查自动创建的间隔分区以及转换为日期格式的 high_value (注释中提到的解释)......
注意:我已经调整了这篇关于 SO 的帖子的逻辑

select 
table_name,
partition_name,
interval,
to_date ( -- convert to date datatype
          trim ( -- trim whitespaces
          '''' from regexp_substr ( 
                     extractvalue ( -- return scalar value of the single text node viz., high_value
                       dbms_xmlgen.getxmltype ( -- converts the results of a SQL query into XML format
                       'select high_value from all_tab_partitions where table_name='''
                                || table_name
                                || ''' and partition_name = '''
                                || partition_name
                                || ''''),
                             '//text()'),
                          '''.*?''')), -- regex pattern matching to fetch value between the first set of quotes
          'syyyy-mm-dd hh24:mi:ss')
          high_value_in_date_format
  FROM all_tab_partitions
 WHERE table_name = 'TESTPART' 
;

|TABLE_NAME |PARTITION_NAME |INTERVAL |HIGH_VALUE_IN_DATE_FORMAT    |
|TESTPART   |SYS_P9064429   |YES      |4/17/2020                    |
|TESTPART   |SYS_P9064428   |YES      |4/16/2020                    |
|TESTPART   |P1             |NO       |1/1/2020                     |

创建一个过程以接受日期并将其与 high_value 匹配以识别指定表中紧接在前的分区并截断/删除该分区...

  create or replace procedure int_part_housekeeping
      ( p_date        date,
        p_table_name  varchar2
      )
  as
      l_part_name     varchar2(30);
  begin

      -- identifying partition based on high value in all_tab_partitions 
    select partition_name
      into l_part_name
      from all_tab_partitions
      where table_name = p_table_name
      and  
         to_date ( -- convert to date datatype
            trim ( -- trim whitespaces
            '''' from regexp_substr ( 
                       extractvalue ( -- return scalar value of the single text node
                         dbms_xmlgen.getxmltype ( -- converts the results of a SQL query into XML format
                         'select high_value from all_tab_partitions where table_name='''
                                  || table_name
                                  || ''' and partition_name = '''
                                  || partition_name
                                  || ''''),
                               '//text()'),
                            '''.*?''')), -- regex pattern matching to fetch value between the first set of quotes
            'syyyy-mm-dd hh24:mi:ss') = p_date
      ;

      -- truncating preceding partition
      dbms_output.put_line('Trucating partition for preceding interval partition :' || l_part_name );    
      execute immediate 'ALTER TABLE ' || p_table_name || ' TRUNCATE PARTITION (' || l_part_name || ')';

      -- dropping preceding partition (note: interval needs to be reset before and after the drop operation)
      dbms_output.put_line('Dropping partition for preceding interval partition :' || l_part_name); 
      execute immediate 'ALTER TABLE ' || p_table_name || ' SET INTERVAL ()';
      execute immediate 'ALTER TABLE ' || p_table_name || ' DROP PARTITION (' || l_part_name || ')';
      execute immediate 'ALTER TABLE ' || p_table_name || ' SET INTERVAL ( NUMTODSINTERVAL(1,''day'') )';

  exception 
      when others then
      dbms_output.put_line(sqlerrm);
      raise;
  end;

执行传递当前日期和表名的过程..

set serveroutput on;
begin
    int_part_housekeeping(date'2020-04-16','TESTPART');
end;

Output:
Trucating partition for preceding interval partition :SYS_P9064428
Dropping partition for preceding interval partition :SYS_P9064428
 PL/SQL procedure successfully completed.

检查是否删除了所需的分区...

|TABLE_NAME |PARTITION_NAME |INTERVAL |HIGH_VALUE_IN_DATE_FORMAT    |
|TESTPART   |SYS_P9064429   |NO       |4/17/2020                    |
|TESTPART   |P1             |NO       |1/1/2020                     |

然后,您可以按需执行此过程或使用 dbms 调度程序在特定时间运行。

如果这符合您的要求,请随时接受投票

于 2020-04-15T07:03:54.123 回答