我有一个基于日和小时(子分区)分区的表。
我希望在任何给定时间保留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" ) ;
此致
答案 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_TIME
,TARGET_DATE
和TARGET_HOUR
。请注意,每个 DATE
或TIMESTAMP
值包含日期和时间组件。使用简单的分区,从技术上讲它将是相同的,但维护将更容易。像这样定义表:
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;