Oracle 单体大表删除方法

来源:这里教程网 时间:2026-03-03 18:12:28 作者:

本文档介绍了大表清理的几种方法。

注意:

避免终止delete  大事务,因为会产生回滚,耗费更长的时间。

尝试将大型的delete/truncate  拆分为多个事务。

 

 

创建测试表

conn joe/joe;

 

create table ob1 as select * from dba_objects;

insert into ob1 select * from ob1;

insert into ob1 select * from ob1;

...

create table ob2 as select * from ob1;

create table ob3 as select * from ob1;

create table ob4 as select * from ob1;

 

 

SQL> select count(*) from ob1;

 

  COUNT(*)

----------

   5536064

 

SQL> select count(*) from ob2;

 

  COUNT(*)

----------

   5536064

 

SQL> select count(*) from ob3;

 

  COUNT(*)

----------

   5536064

 

SQL> select count(*) from ob4;

 

  COUNT(*)

----------

   5536064

 

SQL> select count(*) from ob1 where object_type='SYNONYM';

 

  COUNT(*)

----------

   2181440

 

SQL> select count(*) from ob2 where object_type='SYNONYM';

 

  COUNT(*)

----------

   2181440

 

SQL> select count(*) from ob3 where object_type='SYNONYM';

 

  COUNT(*)

----------

   2181440  

 

SQL> select count(*) from ob4 where object_type='SYNONYM';

 

  COUNT(*)

----------

   2181440

 

SQL> select bytes/1024/1024m from dba_segments where segment_name='OB1';

 

         M

----------

       624

 

SQL> select bytes/1024/1024m from dba_segments where segment_name='OB2';

 

         M

----------

       624

 

SQL> select bytes/1024/1024m from dba_segments where segment_name='OB3';

 

         M

----------

       624 

 

SQL> select bytes/1024/1024m from dba_segments where segment_name='OB4';

 

         M

----------

       624

 

重启数据库,并关闭归档(为了避免删除的时候产生大量归档消耗空间),然后进行测试。

 

传统方式删除

SQL> set timing on

SQL> delete ob1 where object_type='SYNONYM';

2181440 rows deleted.

Elapsed: 00:03:53.23

 

SQL> commit;

 

Commit complete.

 

Elapsed: 00:00:00.27

SQL> alter system checkpoint;

 

System altered.

 

Elapsed: 00:00:37.95

SQL> alter system flush buffer_cache;

 

System altered.

 

Elapsed: 00:00:10.84

 

 

使用DBMS_PARALLEL_EXECUTE  包进行删除

 

SET SERVEROUTPUT ON

BEGIN

  DBMS_PARALLEL_EXECUTE.DROP_TASK ('test_task');

EXCEPTION WHEN OTHERS THEN

NULL;

END;

/

 

DECLARE

  l_task     VARCHAR2(30) := 'test_task';

  l_sql_stmt VARCHAR2(32767);

  l_try      NUMBER;

  l_status   NUMBER;

BEGIN

  -- Create the TASK

  DBMS_PARALLEL_EXECUTE.CREATE_TASK (task_name => l_task);

  -- Chunk the table by the ROWID

  DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_ROWID

  (

    TASK_NAME   => l_task,

    TABLE_OWNER => 'JOE',

    TABLE_NAME  => 'OB2',

    BY_ROW      => TRUE,

    CHUNK_SIZE  => 2500

  );

  -- DML to be execute in parallel

  l_sql_stmt := 'delete OB2 where object_type = ''SYNONYM'' and rowid BETWEEN :start_id AND :end_id';

  -- Run the task

  DBMS_PARALLEL_EXECUTE.RUN_TASK

  (

    TASK_NAME      => l_task,

    SQL_STMT       => l_sql_stmt,

    LANGUAGE_FLAG  => DBMS_SQL.NATIVE,

    PARALLEL_LEVEL => 1

  );

  -- If there is error, RESUME it for at most 2 times.

  l_try := 0;

  l_status := DBMS_PARALLEL_EXECUTE.TASK_STATUS(l_task);

  WHILE(l_try < 2 and l_status != DBMS_PARALLEL_EXECUTE.FINISHED)

  LOOP

    l_try := l_try + 1;

    DBMS_PARALLEL_EXECUTE.RESUME_TASK(l_task);

    l_status := DBMS_PARALLEL_EXECUTE.TASK_STATUS(l_task);

  END LOOP;

  -- Done with processing; drop the task

  DBMS_PARALLEL_EXECUTE.DROP_TASK(l_task);

EXCEPTION WHEN OTHERS THEN

  DBMS_OUTPUT.PUT_LINE('Error in the code :' || SQLERRM);

END;

/

 

PL/SQL procedure successfully completed.

 

Elapsed: 00:03:00.69

 

SQL> alter system checkpoint;

 

System altered.

 

SQL> alter system flush buffer_cache;

 

System altered.

 

 

涉及相关试图:

SELECT * FROM DBA_PARALLEL_EXECUTE_TASKS;

SELECT * FROM DBA_PARALLEL_EXECUTE_CHUNKS;

SELECT count(1) FROM DBA_PARALLEL_EXECUTE_CHUNKS;

select status, count(*) from user_parallel_execute_chunks group by status;

select D.owner,D.job_name,D.JOB_STYLE,D.JOB_TYPE,D.JOB_ACTION from dba_scheduler_jobs d where d.owner='JOE';

select sid, serial#, status, PROGRAM, SQL_ID, event from v$session where action like 'TASK$%';

 

 

使用rowid  进行删除

 

declare

  cursor cur_rowid is

    select dbms_rowid.rowid_create(1,

                                   b.data_object_id,

                                   a.relative_fno,

                                   a.block_id,

                                   0) begin_rowid,

           dbms_rowid.rowid_create(1,

                                   b.data_object_id,

                                   a.relative_fno,

                                   a.block_id + blocks - 1,

                                   999) end_rowid

      from dba_extents a, dba_objects b

     where a.segment_name = b.object_name

       and a.owner = b.owner

       and b.object_name = 'OB3'

       and b.owner = 'JOE'

     order by a.relative_fno, a.block_id;

  r_sql varchar2(4000);

begin

  FOR cur in cur_rowid LOOP

    r_sql := 'delete OB3 where object_type =' || '''' || 'SYNONYM' || '''' ||

             ' and rowid between :1 and :2';

    EXECUTE IMMEDIATE r_sql

      using cur.begin_rowid, cur.end_rowid;

    COMMIT;

  END LOOP;

end;

/

 

PL/SQL procedure successfully completed.

 

Elapsed: 00:02:52.10

 

 

SQL> alter system checkpoint;

 

System altered.

 

SQL> alter system flush buffer_cache;

 

System altered.

 

 

 

使用rowid  分片的方式进行删除

 

vi rowid_chunk.sql

 

set verify off

undefine rowid_ranges

undefine segment_name

undefine owner

set head off

set pages 0

set trimspool on

 

select 'where rowid between ''' ||sys.dbms_rowid.rowid_create(1, d.oid, c.fid1, c.bid1, 0) ||''' and ''' ||sys.dbms_rowid.rowid_create(1, d.oid, c.fid2, c.bid2, 9999) || '''' ||';'

  from (select distinct b.rn,

                        first_value(a.fid) over(partition by b.rn order by a.fid, a.bid rows between unbounded preceding and unbounded following) fid1,

                        last_value(a.fid) over(partition by b.rn order by a.fid, a.bid rows between unbounded preceding and unbounded following) fid2,

                        first_value(decode(sign(range2 - range1),

                                           1,

                                           a.bid +

                                           ((b.rn - a.range1) * a.chunks1),

                                           a.bid)) over(partition by b.rn order by a.fid, a.bid rows between unbounded preceding and unbounded following) bid1,

                        last_value(decode(sign(range2 - range1),

                                          1,

                                          a.bid +

                                          ((b.rn - a.range1 + 1) * a.chunks1) - 1,

                                          (a.bid + a.blocks - 1))) over(partition by b.rn order by a.fid, a.bid rows between unbounded preceding and unbounded following) bid2

          from (select fid,

                       bid,

                       blocks,

                       chunks1,

                       trunc((sum2 - blocks + 1 - 0.1) / chunks1) range1,

                       trunc((sum2 - 0.1) / chunks1) range2

                  from (select /*+ rule */

                         relative_fno fid,

                         block_id bid,

                         blocks,

                         sum(blocks) over() sum1,

                         trunc((sum(blocks) over()) / &&rowid_ranges) chunks1,

                         sum(blocks) over(order by relative_fno, block_id) sum2

                          from dba_extents

                         where segment_name = upper('&&segment_name')

                           and owner = upper('&&owner'))

                 where sum1 > &&rowid_ranges) a,

               (select rownum - 1 rn

                  from dual

                connect by level <= &&rowid_ranges) b

         where b.rn between a.range1 and a.range2) c,

       (select max(data_object_id) oid

          from dba_objects

         where object_name = upper('&&segment_name')

           and owner = upper('&&owner')

           and data_object_id is not null) d

           /

 

@rowid_chunk.sql

Enter value for rowid_ranges: 1

Enter value for segment_name: ob4

Enter value for owner: joe

 

 

SQL> delete OB4 where object_type ='SYNONYM' and rowid between 'AAAWCUAAEAAALaAAAA' and 'AAAWCUAAEAACix/CcP';

 

2181440 rows deleted.

 

Elapsed: 00:02:56.64

 

SQL> commit;

 

Commit complete.

相关推荐