【问题标题】:How to truncate oracle created partition on daily basis [closed]如何每天截断oracle创建的分区[关闭]
【发布时间】:2020-04-15 03:27:04
【问题描述】:

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

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

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

由于删除会产生碎片,因此我被要求使用 truncate 或 drop。

【问题讨论】:

    标签: oracle partitioning


    【解决方案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  |
    

    检查自动创建的间隔分区以及转换为日期格式的高值(在 cmets 旁边提到的解释)...
    注意:我已经改编了来自this 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 调度程序在特定时间运行。

    如果这符合您的要求,请随时 acceptvote

    【讨论】:

      猜你喜欢
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 2018-02-27
      • 1970-01-01
      • 2020-01-10
      • 1970-01-01
      • 2016-08-01
      • 1970-01-01
      相关资源
      最近更新 更多