如本question所述,我有以下表格:
create table prova_log(
id_dispositive number,
type number,
date_verification date,
status number
)
partition by range (date_verification) interval (numtoyminterval(1,'MONTH'))
subpartition by list (type)
subpartition TEMPLATE (
SUBPARTITION type1 VALUES (1),
SUBPARTITION type2 VALUES (2),
SUBPARTITION type3 VALUES (3),
SUBPARTITION type4 VALUES (4)
)
(
partition p0816 values less than (to_date('01/09/2016','dd/mm/yyyy'))
);
如您所见,我将第一个分区命名为 p0816 。但下一个分区将以随机名称生成吗?
我需要在oracle工作中以编程方式清除表。 我正在考虑 - 因为我的方案是处理1B行/月 - 来删除分区。但是我该怎么做呢?如何按日期范围查找表分区?
我想做类似的事情:
alter table prova_log drop partition XPTO
" XPTO"将是一个随机分区名称,但按日期范围选择 - 比如说3个月之前。换句话说,删除2016/08/01之前的所有内容
答案 0 :(得分:1)
我像这样使用脚本smt(将表名更改为你的)
declare
l_limit_date date := sysdate;
begin
for c in (select table_name,
partition_name,
interval,
high_value_in_date_format
from (select table_name,
partition_name,
interval,
to_date(trim('''' from regexp_substr(extractvalue(dbms_xmlgen.
getxmltype('select high_value from user_tab_partitions where table_name=''' ||
table_name ||
''' and partition_name = ''' ||
partition_name || ''''),
'//text()'),
'''.*?''')),
'syyyy-mm-dd hh24:mi:ss') high_value_in_date_format
from user_tab_partitions
where table_name = 'TEST_LOG')
where high_value_in_date_format <= l_limit_date
order by high_value_in_date_format)
loop
if (c.interval = 'NO') then
execute immediate 'alter table TEST_LOG truncate partition ' || c.partition_name;
else
execute immediate 'alter table TEST_LOG drop partition ' || c.partition_name;
end if;
end loop;
end;
/
答案 1 :(得分:0)
在Oracle中,您有两种方法来处理分区,它们是等效的。
ALTER TABLE prova_log DROP PARTITION p0816;
ALTER TABLE prova_log DROP PARTITION FOR ( to_date('01/09/2016','dd/mm/yyyy') );
如果您想解决SUBPARTITION,语法将如下:
ALTER TABLE prova_log TRUNCATE SUBPARTITION FOR ( to_date('01/09/2016','dd/mm/yyyy'), 2 );
为了删除(或截断)分区,我有这个通用的PL / SQL包。最棘手的部分是将HIGH_VALUE
LONG
数据类型转换为可用值。
FUNCTION DailyPartition(tableName IN VARCHAR2) RETURN BOOLEAN IS
EXPRESSION_IS_OF_WRONG_TYPE EXCEPTION;
PRAGMA EXCEPTION_INIT(EXPRESSION_IS_OF_WRONG_TYPE, -6550);
ds INTERVAL DAY TO SECOND;
ym INTERVAL YEAR TO MONTH;
str VARCHAR2(1000);
BEGIN
SELECT INTERVAL INTO str FROM USER_PART_TABLES WHERE TABLE_NAME = tableName;
EXECUTE IMMEDIATE 'BEGIN :ret := '||str||'; END;' USING OUT ym;
RETURN FALSE;
EXCEPTION
WHEN EXPRESSION_IS_OF_WRONG_TYPE THEN
EXECUTE IMMEDIATE 'BEGIN :ret := '||str||'; END;' USING OUT ds;
RETURN TRUE;
END DailyPartition;
PROCEDURE DropPartition(tableName IN VARCHAR2, ts IN TIMESTAMP) IS
PARTITION_DOES_NOT_EXIST EXCEPTION;
PRAGMA EXCEPTION_INIT(PARTITION_DOES_NOT_EXIST, -2149);
sqlstr VARCHAR2(1000);
BEGIN
sqlstr := 'ALTER TABLE '||tableName||' DROP PARTITION FOR (TIMESTAMP '''||TO_CHAR(ts, 'yyyy-mm-dd hh24:mi:ss')||''') UPDATE GLOBAL INDEXES';
EXECUTE IMMEDIATE sqlstr;
EXCEPTION
WHEN PARTITION_DOES_NOT_EXIST THEN
NULL;
END DropPartition;
PROCEDURE CleanupPartitions IS
sqlstr VARCHAR2(10000);
ts TIMESTAMP;
tableName VARCHAR2(30) := 'PROVA_LOG';
CURSOR TabPartitions IS
SELECT TABLE_NAME, PARTITION_NAME, HIGH_VALUE
FROM USER_TAB_PARTITIONS
WHERE TABLE_NAME = tableName
AND PARTITION_NAME <> 'P0816' -- Inital partition cannot be dropped
ORDER BY 1,2;
BEGIN
ts := ADD_MONTHS(TRUNC(LOCALTIMESTAMP) - INTERVAL '1' DAY, -6);
IF DailyPartition(tableName) THEN
DropPartition(tableName, ts);
IF EXTRACT(DAY FROM ts) >= 30 THEN
DropPartition(tab, ts - INTERVAL '1' DAY);
END IF;
IF TO_CHAR(ts, 'MM-DD') = '08-31' THEN
-- Ensure proper cleanup for February
DropPartition(tableName, ts - INTERVAL '2' DAY);
DropPartition(tableName, ts - INTERVAL '3' DAY);
END IF;
ELSE
DropPartition(tableName, ts);
END IF;
END CleanupPartitions;
保留时间为6个月。根据您的需要制作它应该没有问题。您甚至可以多次调用过程CleanupPartitions;
。通常,它将每月或每天由调度程序作业执行一次。
该软件包适用于每日和每月分区。
答案 2 :(得分:0)
无需使用随机名称,根据日期使用可预测的分区名称。
来自文档的示例,命名分区(Maintaining Partitions):
ALTER TABLE sales ADD
PARTITION sales_q1_2007 VALUES LESS THAN (TO_DATE('01-APR-2007','dd-MON-yyyy')),
PARTITION sales_q2_2007 VALUES LESS THAN (TO_DATE('01-JUL-2007','dd-MON-yyyy')),
PARTITION sales_q3_2007 VALUES LESS THAN (TO_DATE('01-OCT-2007','dd-MON-yyyy')),
PARTITION sales_q4_2007 VALUES LESS THAN (TO_DATE('01-JAN-2008','dd-MON-yyyy'))
;
此外,如果您始终删除尾部分区,则不一定需要事先知道名称。您可以从数据字典(ALL_TAB_PARTITIONS,ALL_PART_TABLES等)查询尾部分区。
我会使用易于记忆和编码的命名方案。使用月份和年份,如果您需要更多粒度,一周或一个月内的某个序号,那么对具有LIKE子句的字典的查询应该可以满足您的需求。