【问题标题】:How to drop partitions based on specific retention period?如何根据特定保留期删除分区?
【发布时间】:2019-01-15 16:54:11
【问题描述】:
    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;

我正在尝试为循环语句添加更多粒度,因此我希望将其延长几天,而不是仅仅每月删除分区。仅供参考,记录是从配置表中获取的,其中包括分区表的详细信息(表所有者、名称和保留期 - 数据类型 NUMBER)。因此,我不知道该怎么做。非常感谢任何帮助。

【问题讨论】:

  • 你为什么一次又一次地问同样的问题? stackoverflow.com/questions/54148136/…stackoverflow.com/questions/53936930/…stackoverflow.com/questions/53837937/…(甚至一次又一次出现同样的错误)?
  • 什么是p_retention_period?几天还是几个月?甚至数周、数年、数小时……?
  • @WernfriedDomscheit 首先,虽然我问的是关于相同程序的问题,但我之前问的问题与我在这篇文章中问的问题不同,所以我不确定你问的意思同样的问题一次又一次地出现同样的错误? p_retention_period 也是几个月 atm 但我想将其更改为天、周等。
  • 有错我的意思是to_date(substr(partition_rec.high_value, ...。如果您调用您的程序,例如purge_partitions('OWNER_NAME', 'TABLE_NAME', 6); - 您怎么知道6 是指“6 周”还是“6 天”?
  • 是的,这就是我的实际问题,我如何区分代码中的 6 个月、6 周、6 天?我知道 HIGH_VALUE 问题 - 我会尽快进行更改。

标签: oracle partitioning sysdate


【解决方案1】:

恕我直言,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的专利。

【讨论】:

  • 由于 TO 想要编写一个通用过程,我不建议使用分区扩展名。假设您运行 ... DROP PARTITION FOR (DATE '2019-01-01') 并且您的分区间隔为 1 个月 - 您将删除当前分区。或者分区间隔是 12 小时 - 你会删除太少的分区。
【解决方案2】:

您的程序有语法错误(例如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

【讨论】:

  • 如何在包规范中声明游标 TabPartitions?
  • 只需将其写入包规范而不是过程中。
猜你喜欢
  • 2022-01-01
  • 2018-06-13
  • 1970-01-01
  • 2012-09-04
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
  • 2018-10-08
相关资源
最近更新 更多