We have an requirement, where we need to purge portion of data from huge table. After much discussion, we have decided go to like
1. create temp table
2. populate only relevant data from main table to temp table
3. drop main table.
4. rename temp table to main table and recreate missing indexes.
there are various approach to do this. But instead we have gone with something like split the big table in to logical split using rowid and with each logical split populate the temp table parallel.
create table scuser.tab1_bk as select * from scuser.tab1 where 1=2;
alter table scuser.tab1_bk nologging;
truncate table scuser.tab1_bk;
Drop table split_rowid purge;
CREATE TABLE split_rowid as select distinct grp,
first_value(relative_fno) over
(partition by grp order by relative_fno, block_id
rows between unbounded preceding and unbounded following) lo_fno,
first_value(block_id ) over
(partition by grp order by relative_fno, block_id
rows between unbounded preceding and unbounded following) lo_block,
last_value(relative_fno) over
(partition by grp order by relative_fno, block_id
rows between unbounded preceding and unbounded following) hi_fno,
last_value(block_id+blocks-1) over
(partition by grp order by relative_fno, block_id
rows between unbounded preceding and unbounded following) hi_block,
sum(blocks) over (partition by grp) sum_blocks
from (
select relative_fno,
block_id,
blocks,
trunc( (sum(blocks) over (order by relative_fno, block_id)-0.01) /
(sum(blocks) over ()/&chunk) ) grp
from dba_extents
where segment_name = ('TAB1')
and owner = '&owner' order by block_id
)
/
Create or replace procedure purge_clock(p_no number,lo_rowid rowid,hi_rowid rowid) as
type array is table of scuser.tab1_bk%rowtype;
l_data array;
cursor c is select /+* first_rows */ * from tab1 a where (exists
(select 1 from probsummarym1
where probsummarym1.numberprgn = a.key_char
and a.type = 'problem')
or a.datetime_last_upd > (sysdate-3)
or type <> 'problem')
and substr(name,0,7) <> 'JPASRPT' and rowid between lo_rowid and hi_rowid;;
lv_cnt number:=0;
lv_cnt1 number:=0;
BEGIN
open c;
loop
fetch c bulk collect into l_data LIMIT 10000;
lv_cnt:=lv_cnt+1;
lv_cnt1 := lv_cnt*10000;
dbms_application_info.set_client_info(p_no||' of Clock:'||lv_cnt1);
forall i in 1 .. l_data.count
Insert into scuser.tab1_bk values l_data(i);
COMMIT;
exit when c%notfound;
END LOOP;
CLOSE c;
commit;
END;
/
alter system set job_queue_processes=20;
set serveroutput on;
Declare
cursor c1 is
select rownum no,
dbms_rowid.rowid_create(1,
(select data_object_id from dba_objects where object_name='tab1' and object_type='TABLE'),lo_fno,lo_block,0) lo_rowid,
dbms_rowid.rowid_create(1,
(select data_object_id from dba_objects where object_name='tab1' and object_type='TABLE'),hi_fno,hi_block,32767) hi_rowid
from split_rowid order by no;
lv_job number;
begin
for i in c1 loop
dbms_job.submit(lv_job,'purge_clock('||i.no||','||chr(39)||i.lo_rowid||chr(39)||','||chr(39)||i.hi_rowid||chr(39)||');');
dbms_output.put_line('Job#'||lv_job);
commit;
end loop;
commit;
end;
/