We archive old partitions using exchange partition + transportable tablespace feature.
This time I won't concentrate on archiving partitions but adding old partitions back to table.
So how to add "old" partition at the beginning or in the middle of a table?
My first try was using 'alter table add partition' command but then I received error:
ORA-14074: partition bound must collate higher than that of the last partition
Small demo case with workaround...
First to create partitioned table with global and local indexes:
create table testtab (id number, code number, datum date) partition by range (datum) ( partition part_2009_10 values less than (to_date('01.11.2009','dd.mm.yyyy')), partition part_2009_11 values less than (to_date('01.12.2009','dd.mm.yyyy')), partition part_2009_12 values less than (to_date('01.01.2010','dd.mm.yyyy')), partition part_2010_01 values less than (to_date('01.02.2010','dd.mm.yyyy')) ); -- global index create unique index id_idx on testtab(id); -- local indexes create index code_idx on testtab(code) local ( partition part_2009_10, partition part_2009_11, partition part_2009_12, partition part_2010_01); -- create primary key alter table testtab add constraint pk_id primary key (id) using index;
Populate table:
insert into testtab select level,abs(dbms_random.random), trunc(sysdate)-level from dual connect by level<101; commit;Small check:
SQL> begin 2 dbms_stats.gather_table_stats(ownname=>user,tabname=>'TESTTAB'); 3 end; 4 / PL/SQL procedure successfully completed. select partition_name,high_value,num_rows as "NR", blocks from user_tab_partitions where table_name='TESTTAB'; PARTITION_NAME HIGH_VALUE NR BLOCKS --------------- ---------------------------------------------------------- ----- ------- PART_2009_11 TO_DATE(' 2009-12-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') 30 5 PART_2009_12 TO_DATE(' 2010-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') 31 5 PART_2010_01 TO_DATE(' 2010-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') 17 5 PART_2009_10 TO_DATE(' 2009-11-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') 22 5 4 rows selected.Now to "archive old partition":
-- create new table based on testtab for "archive" data create table tab_2009_10 as select * from testtab where 1=2; alter table tab_2009_10 modify (id not null); create index code_2009_10_idx on tab_2009_10(code); -- exchange "old" partition alter table testtab exchange partition part_2009_10 with table tab_2009_10 including indexes update global indexes; -- drop "old" partition prom partitioned table alter table testtab drop partition part_2009_10 update global indexes; -- select col partition_name for a15 col high_value for a90 select partition_name,high_value from user_tab_partitions where table_name='TESTTAB' order by 1; PARTITION_NAME HIGH_VALUE --------------- ------------------------------------------------------------- PART_2009_11 TO_DATE(' 2009-12-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') PART_2009_12 TO_DATE(' 2010-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') PART_2010_01 TO_DATE(' 2010-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') 3 rows selected. -- select "archived" data from newly created table select min(datum),max(datum),count(*) from tab_2009_10; MIN(DATUM) MAX(DATUM) COUNT(*) ------------------- ------------------- ---------- 10.10.2009 00:00:00 31.10.2009 00:00:00 22 1 row selected.It is now safe to export tab_2009_10 table and archive it somewhere else. But what if I need this archived data to be a part of partitioned table again... First I will try to add partition using "add partition" command:
-- add partition test SQL> alter table testtab add partition part_2009_10 2 values less than (to_date('01.11.2009','dd.mm.yyyy')); alter table testtab add partition part_2009_10 * ERROR at line 1: ORA-14074: partition bound must collate higher than that of the last partitionSo little workaround is needed... We could use "split partition" command to add partition at the beginning of the table:
alter table testtab split partition part_2009_11 at (to_date('01.11.2009','dd.mm.yyyy')) into (partition part_2009_10,partition part_2009_11);Little check:
col partition_name for a15 col high_value for a90 select partition_name,high_value from user_tab_partitions where table_name='TESTTAB' order by 1; PARTITION_NAME HIGH_VALUE --------------- -------------------------------------------------------------- PART_2009_10 TO_DATE(' 2009-11-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') PART_2009_11 TO_DATE(' 2009-12-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') PART_2009_12 TO_DATE(' 2010-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS') PART_2010_01 TO_DATE(' 2010-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS')So PART_2009_10 is again part of partitioned table. Now it is possible to insert archived rows in partitioned table using "insert ... select" command:
insert into testtab select * from tab_2009_10;This is little inconvenient solution when we have to insert many rows, so there is another solution using exchange partition:
alter table testtab exchange partition part_2009_10 2 with table tab_2009_10 including indexes update global indexes; alter table testtab exchange partition part_2009_10 * ERROR at line 1: ORA-14130: UNIQUE constraints mismatch in ALTER TABLE EXCHANGE PARTITIONTo avoid this error I've disabled and re-enabled constraint of partitioned table. NOTE! I don't know if this is appropriate solution so I would be tankful if someone could suggest me better solution.
SQL> alter table testtab disable novalidate constraint PK_ID; Table altered. -- because of disable novalidate pk_id lost not null constraint SQL> alter table tab_2009_10 modify (id null); Table altered. SQL> alter table testtab exchange partition part_2009_10 2 with table tab_2009_10 including indexes update global indexes; Table altered. SQL> alter table testtab enable validate constraint PK_ID; Table altered.For final check I will query "old" data in partitioned table:
SQL> select min(datum),max(datum),count(*) 2 from testtab partition (part_2009_10); MIN(DATUM) MAX(DATUM) COUNT(*) ------------------- ------------------- ---------- 10.10.2009 00:00:00 31.10.2009 00:00:00 22 1 row selected.References: Metalink [ID 727306.1]
Hi,
ReplyDeletecan you explain me why you execute
alter table tab_2009_10 modify (id not null);
After this alter table if I execute exchange I receive this error.
alter table testtab exchange partition part_2009_10 with table tab_2009_10 including indexes update global indexes
*
ERROR at line 1:
ORA-14097: column type or size mismatch in ALTER TABLE EXCHANGE PARTITION
Hi sos,
ReplyDeleteID column in partitioned table is primary key so it is NOT NULL.
I altered ID column to be NOT NULL for table TAB_2009_10 also to be the same as partitioned.
I've just tried test case again and everything worked without any error :/
Is everything working for you without altering ID column for table TAB_2009_10?
Regards,
Marko
Yes,
ReplyDeletebecause you can't exchange partition if structure table/partition are non identical: column null or not null generate ORA-14097 error I suppose
Great blog I enjoyed readiing
ReplyDelete