A recent posting on the OTN database forum (which I didn’t answer correctly on my first attempt) raised the problem of truncating partitions when there are referential integrity constraints in place. Let’s start with a demonstration of the problem:
create table parent (
id number,
v1 varchar2(10),
padding varchar2(100),
constraint p_pk primary key(id) using index local
)
partition by range(id) (
partition p1000 values less than (1000),
partition p2000 values less than (2000),
partition p3000 values less than (3000),
partition p4000 values less than (4000),
partition p5000 values less than (5000)
)
;
create table child (
id_p number,
seq_c number,
v1 varchar2(10),
padding varchar2(100),
constraint c_fk_p foreign key (id_p) references parent,
constraint c_pk primary key (id_p, seq_c) using index local
)
partition by range(id_p) (
partition p1000 values less than (1000),
partition p2000 values less than (2000),
partition p3000 values less than (3000),
partition p4000 values less than (4000),
partition p5000 values less than (5000)
)
;
insert into parent
select
rownum - 1,
rpad(rownum - 1,10),
rpad('x',100)
from
all_objects
where
rownum <= 4000
;
insert into child
select
id,
val,
v1,
padding
from
parent,
(
select 1 val from dual
union all
select 2 val from dual
union all
select 3 val from dual
union all
select 4 val from dual
)
;
-- gather some stats on the two tables.
alter table child truncate partition p4000;
alter table parent truncate partition p4000;
The problem is that you can’t truncate the parent partition because Oracle thinks there may be related data in the child partition – despite the fact that the internal code could be written to see that the partition’s data segment was “new”. The output from the two truncate commands is as follows:
-- the call for the child works
Table truncated.
alter table parent truncate partition p4000
*
ERROR at line 1:
ORA-02266: unique/primary keys in table referenced by enabled foreign keys
You can’t truncate the parent partition unless you disable the foreign key constraint – and it might take quite a long time to re-enable it since we usually only worry about partitioning for large objects.
There is a slightly surprising workaround that might be good enough. If you set the foreign key constraint to novalidate, rather than disable, you can tell Oracle to exchange partitions without checking the validity of the foreign key constraint. So:
create table parent_ex ( id number, v1 varchar2(10), padding varchar2(100), constraint px_pk primary key(id) ) ; create table child_ex ( id_p number, seq_c number, v1 varchar2(10), padding varchar2(100), constraint cx_fk_px foreign key (id_p) references parent_ex, constraint cx_pk primary key (id_p, seq_c) ) ; alter table child modify constraint c_fk_p rely enable novalidate ; alter table child_ex modify constraint cx_fk_px rely enable novalidate ; prompt ============================================================ prompt We can now exchange the child and parent partitions we want. prompt ============================================================ alter table child exchange partition p3000 with table child_ex including indexes without validation ; alter table parent exchange partition p3000 with table parent_ex including indexes without validation ;
Having done the two exchanges, we have two empty partitions in the partitioned table and we can truncate the resulting parent_ex and child_ex tables. If we wanted we could also modify the referential integrity constraint back to validate mode – although this would take some time, of course, and we might just decide that it wasn’t necessary because (we believe) all the old data would be correct, and we may only be worried about making sure that new data will be checked.
The downside to this method is that we need to keep (or recreate) a pair of tables in the right tablespace so that we can do the exchange when we need to; but that doesn’t seem to be a terrible price to pay for the ability to “truncate” a single partition without disabling referential integrity constraints.

In this example the child table could be PARTITION BY REFERENCE(c_fk_p) and then TRUNCATE PARTITION in the parent will be allowed when the corresponding partition in the child is empty.
In general, PARTITION BY REFERENCE is useful if you have tables connected by a referential constraint and you want to equi-partition the child and parent tables. Partition maintenance operations such as ADD, DROP, SPLIT and MERGE PARTITION will cascade implicitly to the child when performed on the parent. Since the rdbms is enforcing equi-partitioning, the enabled ref constraint does not block operations such as TRUNCATE and EXCHANGE PARTITION when the relevant partition of the other table is empty.
Comment by George Eadon — June 5, 2012 @ 5:48 pm UTC Jun 5,2012 |
George,
Thanks for highlighting that possibility. The OP was talking about 10g so the option made available through 11g completely slipped my mind.
Comment by Jonathan Lewis — June 7, 2012 @ 5:47 pm UTC Jun 7,2012 |
Reblogged this on lava kafle kathmandu nepal.
Comment by lkafle — June 6, 2012 @ 2:47 am UTC Jun 6,2012 |
Jonathan
You’ve blogged about such a smilar case several years ago
http://jonathanlewis.wordpress.com/2006/12/10/drop-parent-partition/
Best regards
Comment by Houri Mohamed — June 6, 2012 @ 1:37 pm UTC Jun 6,2012 |
Mohamed,
Thanks for that – I really ought to read my own work from time to time ;)
Interestingly one of the notes I wrote on that blog item claimed that the mechanism described by George Eadon doesn’t work with one particular pattern. However I can’t find the test case to justify the claim, and the quick test I ran based on the description didn’t repeat the problem in 11.1.0.7 or 11.2.0.3, so either there was a limitation in the earliest version that has been addressed, or I was wrong.
Comment by Jonathan Lewis — June 7, 2012 @ 6:04 pm UTC Jun 7,2012 |
Nice Article,
I had also written an Article about Disabling and Enabling Constraints, What precautions to be taken while performing these Operations etc.. in http://www.way2db.in/oracle-constraints.html
Comment by kshashikanth seo (@kshashikanthseo) — June 19, 2012 @ 3:47 am UTC Jun 19,2012 |