2016-12-09 2 views
1

У меня есть эта таблица, как мои основных таблиц (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 типа разбиения таблицы должен соответствовать типу subpartitioning составного раздела

Я предполагаю, что у меня должен быть раздел в моей таблице резервного копирования с тем же именем, что и моя основная секционированная таблица?

Как это сделать?

Я попытался сделать add раздел моей резервной таблицы, но безуспешно. Важно отметить, что все имена разделов являются случайными (оракул генерирует его).

+0

Почему вы хотите скопировать данные/переместить в другую таблицу? Это одно из основных преимуществ многораздельной таблицы, в которой вам не нужны такие материалы. –

+0

@WernfriedDomscheit, потому что у меня есть другая работа, чтобы посчитать эти миллионы строк по диапазону дат. даже секционированный процесс занимает слишком много времени, когда таблица похожа на строки 500M + ... В любом случае ... Я хочу «отбросить» (без потери) более старый valeus, так как они мне больше не нужны. –

ответ

2

Я все еще не понимаю, почему вы хотите переместить разделы, так или иначе у меня есть решение.

Прежде всего, вы можете обратиться раздел либо как

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 
); 
+0

привет, спасибо за ответ .. но я думаю, что это дорого .. Я имею в виду, что у каждого раздела есть как минимум 10M строк ... это займет много времени, чтобы выполнить правильно? –

+0

Посмотрите на мой обновленный ответ. –

+0

Теперь я получаю «несоответствие ограничений внешнего ключа ORA-14128 в разделе обмена альтернативными таблицами» –

1

Вы делаете это неправильно. Вы обмениваете раздел со всеми секционированной таблицы не с ним разделов, просто посмотрите еще одну на свой код

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

+0

Прошу прощения ... Я не понимаю. Мне нужно создать пустую таблицу без раздела и сделать что с ней? –

+0

@MarllonNasser Tom kyte уже решил эту проблему. См. Https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:1238800184155,%7Bpartitions%7D. (сообщение от 02 апреля 2006 г.) Я должен добавить эту ссылку первым. –

Смежные вопросы