【问题标题】:Exchange/Move partitions between tables在表之间交换/移动分区
【发布时间】:2016-12-09 21:46:33
【问题描述】:

我将此表作为我的 表(100M 行):

create table prova_log(
       id_dispositive       number,
       type                 number,
       date_verification    date,
       status               number
)
partition by range (date_verification) interval (NUMTODSINTERVAL(3,'DAY'))
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'))
);

我想用旧值进行某种备份,所以我创建了这个(0 行):

create table prova_log_old (
       id_dispositive       number,
       type                 number,
       date_verification    date,
       status               number
)
partition by range (date_verification) interval (NUMTODSINTERVAL(3,'DAY'))
subpartition by list (type)  
subpartition TEMPLATE (
    SUBPARTITION type1 VALUES (1),
    SUBPARTITION type2 VALUES (2),
    SUBPARTITION type3 VALUES (3),
    SUBPARTITION type4 VALUES (4)
)                          
(
   partition p_old values less than (to_date('01/09/2016','dd/mm/yyyy'))
);

所以我想将旧分区(15 天以上)移动/复制/交换(无论期限如何)到 prova_log_old

为此,我创建了这个工作:

PROCEDURE move_data_from_huge_table
   IS
      -- This will move all data after 'vcountdaystokeepdata' days
      vcountdaystokeepdata        NUMBER := 15;
      vcountdatainsidepartition   NUMBER := 0;
   BEGIN
      FOR item IN
         (SELECT *
            FROM (SELECT partition_name,
                         TO_DATE
                            (TRIM
                                ('''' FROM REGEXP_SUBSTR
                                             (EXTRACTVALUE
                                                 (DBMS_XMLGEN.getxmltype
                                                     (   'select high_value from all_tab_partitions where table_name='''
                                                      || table_name
                                                      || ''' and table_owner = '''
                                                      || table_owner
                                                      || ''' and partition_name = '''
                                                      || partition_name
                                                      || ''''
                                                     ),
                                                  '//text()'
                                                 ),
                                              '''.*?'''
                                             )
                                ),
                             'syyyy-mm-dd hh24:mi:ss'
                            ) high_value
                    FROM all_tab_partitions
                   WHERE table_name = 'PROVA_LOG')
           WHERE high_value < SYSDATE - vcountdaystokeepdata)
      LOOP                 
         EXECUTE IMMEDIATE    'alter table PROVA_LOG EXCHANGE PARTITION '
                           || item.partition_name
                           || ' with table PROVA_LOG_OLD';

         EXECUTE IMMEDIATE    'select count(*) from PROVA_LOG partition ('
                           || item.partition_name
                           || ')'
                      INTO vcountdatainsidepartition;

         IF vcountdatainsidepartition = 0
         THEN
            EXECUTE IMMEDIATE    'ALTER TABLE PROVA_LOG DROP PARTITION '
                              || item.partition_name
                              || '';
         END IF;

      END LOOP;
   END;

但是当我运行程序时,我得到了

ORA-14292 表的分区类型必须匹配复合分区的子分区类型

我假设我的备份表中必须有一个与主分区表同名的分区,对吧?

我怎样才能做到这一点?

我尝试add 一个分区到我的备份表但没有成功。重要的是要提到所有分区的名称都是随机的(oracle 生成它)。

【问题讨论】:

  • 为什么要将数据复制/移动到另一个表?不需要这些东西是分区表的主要好处之一。
  • @WernfriedDomscheit 因为我还有另一项工作是按日期范围计算数百万行。当表像 500M+ 行时,即使分区该过程也需要太长时间......无论如何......我想“删除”(不丢失)旧的 valeus,因为我不再需要它们了。

标签: oracle partitioning


【解决方案1】:

我还是不明白你为什么要移动分区,反正我有办法。

首先,你可以像这样寻址一个分区

SELECT COUNT(*) FROM PROVA_LOG PARTITION (SYS_P7138);

或者你可以这样做

SELECT COUNT(*) FROM PROVA_LOG PARTITION FOR (TO_DATE('2016-10-01', 'YYYY-MM-DD'));

或者如果您更喜欢 DATE 文字

SELECT COUNT(*) FROM PROVA_LOG PARTITION FOR (DATE '2016-10-01');

您的问题的自动解决方案可能是这个:

DECLARE

    CURSOR TabPartitions IS
    SELECT TABLE_NAME, PARTITION_NAME, HIGH_VALUE
    FROM USER_TAB_PARTITIONS 
    WHERE TABLE_NAME = 'PROVA_LOG'
    ORDER BY 1,2;

    ts DATE;

BEGIN
    FOR aPart IN TabPartitions LOOP
        EXECUTE IMMEDIATE 'BEGIN :ret := '||aPart.HIGH_VALUE||'; END;' USING OUT ts;
        IF ts <> DATE '2016-09-10' AND ts < SYSDATE - 15 THEN
            --EXECUTE IMMEDIATE 'INSERT INTO PROVA_LOG_OLD SELECT * FROM PROVA_LOG PARTITION FOR (DATE '''||TO_CHAR(ts, 'yyyy-mm-dd')||''')'; 
            --EXECUTE IMMEDIATE 'ALTER TABLE PROVA_LOG DROP PARTITION FOR (DATE '''||TO_CHAR(ts, 'yyyy-mm-dd')||''') UPDATE GLOBAL INDEXES';
            EXECUTE IMMEDIATE 'ALTER TABLE PROVA_LOG EXCHANGE PARTITION FOR (DATE '''||TO_CHAR(ts, 'yyyy-mm-dd')||''') WITH TABLE PROVA_LOG_OLD INCLUDING INDEXES';
        END IF;
    END LOOP;

END;

你的备份表必须是这样的:

CREATE TABLE prova_log_old (
       id_dispositive       NUMBER,
       TYPE                 NUMBER,
       date_verification    DATE,
       status               NUMBER
)
PARTITION BY LIST (TYPE) 
(
    PARTITION type1 VALUES (1),
    PARTITION type2 VALUES (2),
    PARTITION type3 VALUES (3),
    PARTITION type4 VALUES (4)
);

或根本不分区

CREATE TABLE prova_log_old (
       id_dispositive       NUMBER,
       TYPE                 NUMBER,
       date_verification    DATE,
       status               NUMBER
);

【讨论】:

  • 嘿伙计,谢谢你的回答.. 但我认为这很昂贵.. 我的意思是每个分区至少有 10M 行......这需要很长时间才能执行,对吧?
  • 现在我收到了ORA-14128 foreign key constraint mismatch in alter table exchange partition
  • 我测试了它,对我来说它有效。您是否按照提供的要求创建了新表 prova_log_old
  • 是的...我按照您所说的创建了按列表分区。但是我的主表有一些 FK...
  • 这似乎是个问题。例如,如果你有外键,你就不能运行TRUNCATE TABLE ...。我假设你必须对 EXCHANGE PARTITION 有同样的限制。也许你可以暂时禁用它们。
【解决方案2】:

你做错了。您与所有分区表交换分区而不是分区,只需再看一下您的代码

 EXECUTE IMMEDIATE    'alter table PROVA_LOG EXCHANGE PARTITION '
                           || item.partition_name
                           || ' with table PROVA_LOG_OLD';

如果是交换分区,你应该这样做

  1. 创建没有分区的空表,其结构与 PROVA_LOG 相同,但未分区。

  2. 使用 new_table 交换生产表中的分区

  3. 用 new_table 交换 hist 表中的分区

【讨论】:

  • 对不起...我不明白。我必须创建一个没有分区的空表并用它做什么?
  • @MarllonNasser Tom kyte 已经解决了这个问题。见asktom.oracle.com/pls/asktom/…。 (2006 年 4 月 2 日的消息)我应该先添加这个链接。
猜你喜欢
  • 2023-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-06
  • 2017-12-16
  • 1970-01-01
  • 2016-08-31
  • 2020-05-27
相关资源
最近更新 更多