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 partition
So 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