如何根据特定的保留期限删除分区?

时间:2019-01-15 16:54:11

标签: oracle partitioning sysdate

    PROCEDURE purge_partitions
   (
      p_owner            IN VARCHAR2
     ,p_name             IN VARCHAR2
     ,p_retention_period IN NUMBER
   ) IS
   BEGIN
      FOR partition_rec IN (SELECT partition_name
                                  ,high_value
                              FROM dba_tab_partitions
                             WHERE table_owner = p_owner
                               AND table_name = p_name)

      --drop partitions older than specified retention preriod
      LOOP
         IF SYSDATE >= add_months(to_date(substr(partition_rec.high_value
                                                ,12
                                                ,19)
                                         ,'YYYY-MM-DD HH24:MI:SS')
                                 ,p_retention_period)
         THEN
            execute_immediate('ALTER TABLE ' || p_owner || '.' ||
                              p_name || ' DROP PARTITION ' ||
                              partition_rec.partition_name);
         END IF;
      END LOOP;
   END purge_partitions;

我正在尝试向循环语句添加更多的粒度,因此,我不仅希望每月删除分区,而且还要延长几天的时间。同样,仅供参考,记录是从Config标签中获取的,Config标签中包含分区表的详细信息(表所有者,名称和保留期-数据类型NUMBER)。因此,我不确定该如何进行。非常感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

恕我直言,列HIGH_VALUE的数据类型为LONG,因此在PL / SQL中很难使用。 但是无论如何您都不需要使用,而是有构造ALTER TABLE ... DROP PARTITION FOR (to_date(....)) 。因此,您根本不必处理生成的分区名称。

  

下面的示例从sales表中删除2007年9月的时间间隔分区。只有本地索引,因此没有索引无效。

ALTER TABLE sales DROP PARTITION FOR(TO_DATE('01-SEP-2007','dd-MON-yyyy'));

PS:该SQL扩展似乎已获得Oracle的专利。

答案 1 :(得分:0)

您的过程存在语法错误(例如execute_immediate(...))。

一个工作程序就是这个。您应该将其命名为drop_partitions而不是purge_partitions,因为您删除了这些分区。使用ALTER TABLE ... TRUNCATE PARTITION ...,也可以进行“清除”:

CREATE OR REPLACE PROCEDURE drop_partitions(
   p_owner IN VARCHAR2, 
   p_name IN VARCHAR2, 
   p_retention_period IN INTERVAL DAY TO SECOND) IS

    ts TIMESTAMP;

    CURSOR TabPartitions IS 
    SELECT partition_name, high_value 
    FROM dba_tab_partitions 
    WHERE table_owner = p_owner 
        AND table_name = p_name;

BEGIN

    FOR partition_rec IN TabPartitions LOOP 
        EXECUTE IMMEDIATE 'BEGIN :ret := '||partition_rec.HIGH_VALUE||'; END;' USING OUT ts;
        IF ts < SYSTIMESTAMP - p_retention_period THEN
            --drop partitions older than specified retention preriod
            EXECUTE IMMEDIATE 'ALTER TABLE ' || p_owner ||'.'||p_name 
                 || ' DROP PARTITION ' || partition_rec.partition_name || ' UPDATE GLOBAL INDEXES';
        END IF;
    END LOOP;

END drop_partitions;

然后您可以像这样调用该过程

purge_partitions('OWNER_NAME', 'TABLE_NAME', INTERVAL '60' DAY);
purge_partitions('OWNER_NAME', 'TABLE_NAME', NUMTODSINTERVAL(100, 'day'));

注意,您在Oracle中也有YEAR TO MONTH INTERVAL。如果您也想使用此功能,则还必须重载该过程,即创建第二个过程:

CREATE OR REPLACE PROCEDURE drop_partitions(
   p_owner IN VARCHAR2, 
   p_name IN VARCHAR2, 
   p_retention_period IN INTERVAL YEAR TO MONTH) IS

   ... rest would be exactly the same as above.

请注意,对于INTERVAL YEAR TO MONTH,您会得到timestamp '2019-03-31 00:00:00' - INTERVAL '1' MONTH之类的计算例外,请参阅Datetime/Interval Arithmetic