表分区清理

时间:2017-08-01 08:56:01

标签: oracle partitioning

我有一个基于日和小时(子分区)分区的表。

我希望在任何给定时间保留10小时的数据,并希望删除早期的分区。日期更改时如何管理?例如,为8月2日的第一个小时和8月1日的9个分区保留一个分区?

任何输入都会有很大的帮助。

表定义是,

  CREATE TABLE "MY_SCHEMA"."MY_TABLE" 
   (    "TARGET_TIME" TIMESTAMP (6), 
    "TARGET_DATE" DATE, 
    "TARGET_HOUR" NUMBER GENERATED ALWAYS AS (EXTRACT(HOUR FROM "TARGET_TIME")) VIRTUAL , 
    "MY_ID" NUMBER(10,0), 
    "MY_INDEX" NUMBER(10,0), 
    "MY_STATUS" NUMBER(10,0)
   ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255  NOLOGGING 
  STORAGE(
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "MYTABLESPACE" 
  PARTITION BY RANGE ("TARGET_DATE") INTERVAL (INTERVAL '1' DAY) 
  SUBPARTITION BY LIST ("TARGET_HOUR") 
  SUBPARTITION TEMPLATE ( 
    SUBPARTITION "HOUR00" VALUES ( 0 ), 
    SUBPARTITION "HOUR01" VALUES ( 1 ), 
    SUBPARTITION "HOUR02" VALUES ( 2 ), 
    SUBPARTITION "HOUR03" VALUES ( 3 ), 
    SUBPARTITION "HOUR04" VALUES ( 4 ), 
    SUBPARTITION "HOUR05" VALUES ( 5 ), 
    SUBPARTITION "HOUR06" VALUES ( 6 ), 
    SUBPARTITION "HOUR07" VALUES ( 7 ), 
    SUBPARTITION "HOUR08" VALUES ( 8 ), 
    SUBPARTITION "HOUR09" VALUES ( 9 ), 
    SUBPARTITION "HOUR10" VALUES ( 10 ), 
    SUBPARTITION "HOUR11" VALUES ( 11 ), 
    SUBPARTITION "HOUR12" VALUES ( 12 ), 
    SUBPARTITION "HOUR13" VALUES ( 13 ), 
    SUBPARTITION "HOUR14" VALUES ( 14 ), 
    SUBPARTITION "HOUR15" VALUES ( 15 ), 
    SUBPARTITION "HOUR16" VALUES ( 16 ), 
    SUBPARTITION "HOUR17" VALUES ( 17 ), 
    SUBPARTITION "HOUR18" VALUES ( 18 ), 
    SUBPARTITION "HOUR19" VALUES ( 19 ), 
    SUBPARTITION "HOUR20" VALUES ( 20 ), 
    SUBPARTITION "HOUR21" VALUES ( 21 ), 
    SUBPARTITION "HOUR22" VALUES ( 22 ), 
    SUBPARTITION "HOUR23" VALUES ( 23 ) ) 
 (PARTITION "DEFAULT_20170101"  VALUES LESS THAN (TO_DATE(' 2017-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) 
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 
  STORAGE(
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "MYTABLESPACE" ) ;

此致

1 个答案:

答案 0 :(得分:0)

PROCEDURE MaintainPartitions(givenTime IN TIMESTAMP DEFAULT LOCALTIMESTAMP) IS 

    CURSOR SubParts IS
    SELECT TABLE_NAME, PARTITION_NAME, SUBPARTITION_NAME, 
        part.HIGH_VALUE AS PART_HIGH_VALUE, 
        subpart.HIGH_VALUE as SUB_HIGH_VALUE
    FROM ALL_TAB_PARTITIONS part
        JOIN ALL_TAB_SUBPARTITIONS subpart USING (OWNER, TABLE_NAME, PARTITION_NAME)
    WHERE OWNER = 'MY_SCHEMA'
        AND TABLE_NAME = 'MY_TABLE'
    ORDER BY PARTITION_POSITION, SUBPARTITION_POSITION;

    CURSOR TabParts IS
    SELECT TABLE_NAME, PARTITION_NAME
    FROM ALL_TAB_PARTITIONS part
    WHERE OWNER = 'MY_SCHEMA'
        AND TABLE_NAME = 'MY_TABLE'
    ORDER BY PARTITION_POSITION;

    cur SYS_REFCURSOR;
    r INTEGER;
    highValue TIMESTAMP;

BEGIN
   -- Truncate old subpartitions
   FOR aSubPart IN SubParts LOOP
      EXECUTE IMMEDIATE 'BEGIN :ret := '||aSubPart.PART_HIGH_VALUE||' + INTERVAL '''||aSubPart.SUB_HIGH_VALUE||''' HOUR; END;' 
          USING OUT highValue;
      IF highValue < givenTime - INTERVAL '10' HOUR THEN
          EXECUTE IMMEDIATE 'ALTER TABLE '||aSubPart.TABLE_NAME||' TRUNCATE SUBPARTITION '||aSubPart.SUBPARTITION_NAME||' UPDATE INDEXES';
      END IF;
   END LOOP;

   -- Drop empty partitions
   FOR aPart IN TabParts LOOP
       OPEN cur FOR 'SELECT ROWNUM FROM '||aPart.TABLE_NAME||' PARTITION ('||aPart.PARTITION_NAME||') WHERE ROWNUM <= 1';
       FETCH cur INTO r;
       IF cur%NOTFOUND THEN
          EXECUTE IMMEDIATE 'ALTER TABLE '||aPart.TABLE_NAME||' DROP PARTITION '||aPart.PARTITION_NAME||' UPDATE INDEXES';
       END IF;
       CLOSE cur;    
   END LOOP;
END;

第一次运行此程序时,您可能会获得ORA-14758: Last partition in the range section cannot be dropped 在这种情况下做

alter table MY_TABLE set interval ();
alter table MY_TABLE DROP PARTITION ...;
alter table MY_TABLE set INTERVAL(INTERVAL '1' DAY);
顺便说一句,为什么你要按小时分区?我认为没有任何理由。 我担心你滥用TARGET_TIMETARGET_DATETARGET_HOUR。请注意,每个 DATETIMESTAMP值包含日期时间组件。使用简单的分区,从技术上讲它将是相同的,但维护将更容易。像这样定义表:

CREATE TABLE MY_SCHEMA.MY_TABLE
   (    TARGET_TIME TIMESTAMP (6), 
    MY_ID NUMBER(10,0), 
    MY_INDEX NUMBER(10,0), 
    MY_STATUS NUMBER(10,0)
   ) 
  TABLESPACE MYTABLESPACE
  PARTITION BY RANGE (TARGET_TIME) INTERVAL (INTERVAL '1' HOUR) 
 (PARTITION "DEFAULT_20170101"  VALUES LESS THAN (TIMESTAMP '2017-01-01 00:00:00');

在这种情况下,上述程序会更简单:

PROCEDURE MaintainPartitions(givenTime IN TIMESTAMP DEFAULT LOCALTIMESTAMP) IS 

    CURSOR TabParts IS
    SELECT TABLE_NAME, PARTITION_NAME, HIGH_VALUE
    FROM ALL_TAB_PARTITIONS part
    WHERE OWNER = 'MY_SCHEMA'
        AND TABLE_NAME = 'MY_TABLE'
    ORDER BY PARTITION_POSITION;

    highValue TIMESTAMP;

BEGIN
    FOR aPart IN TabParts LOOP
      EXECUTE IMMEDIATE 'BEGIN :ret := '||aPart.HIGH_VALUE||'; END;' 
          USING OUT highValue;
      IF highValue < givenTime - INTERVAL '10' HOUR THEN
          EXECUTE IMMEDIATE 'ALTER TABLE '||aPart.TABLE_NAME||' DROP PARTITION '||aPart.PARTITION_NAME||' UPDATE INDEXES';
      END IF;
   END LOOP;
END;