清理CLOB

create or replace procedure show_space(v_segment_name   in varchar2,  
                                       v_segment_owner  in varchar2 default user,  
                                       v_segment_type   in varchar2 default 'TABLE',  
                                       p_analyzed       in varchar2 default 'Y',  
                                       p_partition_name in varchar2 default null) as  
  p_segment_name  varchar2(30);  
  p_segment_owner varchar2(30);  
  p_segment_type  varchar2(30);  
  p_space         varchar2(30);  
  
  l_unformatted_blocks number;  
  l_unformatted_bytes  number;  
  l_fs1_blocks         number;  
  l_fs1_bytes          number;  
  l_fs2_blocks         number;  
  l_fs2_bytes          number;  
  l_fs3_blocks         number;  
  l_fs3_bytes          number;  
  l_fs4_blocks         number;  
  l_fs4_bytes          number;  
  l_full_blocks        number;  
  l_full_bytes         number;  
  
  l_free_blks          number;  
  l_total_blocks       number;  
  l_total_bytes        number;  
  l_unused_blocks      number;  
  l_unused_bytes       number;  
  l_lastusedextfileid  number;  
  l_lastusedextblockid number;  
  l_last_used_block    number;  
  
  procedure p(p_label in varchar2, p_num in number) is  
  begin  
    dbms_output.put_line(rpad(p_label, 40, '.') || p_num);  
  end;  
begin  
  p_segment_name  := upper(v_segment_name);  
  p_segment_owner := upper(v_segment_owner);  
  p_segment_type  := upper(v_segment_type);  
  
  if (p_segment_type = 'I' or p_segment_type = 'INDEX') then  
    p_segment_type := 'INDEX';  
  elsif (p_segment_type = 'T' or p_segment_type = 'TABLE') then  
    p_segment_type := 'TABLE';  
  elsif (p_segment_type = 'C' or p_segment_type = 'CLUSTER') then  
    p_segment_type := 'CLUSTER';  
  end if;  
  
  execute immediate 'select ts.segment_space_management from dba_segments seg, dba_tablespaces ts where seg.segment_name = :p_segname and (:p_partition is null or seg.partition_name = :p_partition) and seg.owner = :p_owner and seg.tablespace_name = ts.tablespace_name'  
    into p_space  
    using p_segment_name, p_partition_name, p_partition_name, p_segment_owner;  
  
  dbms_space.unused_space(segment_owner             => p_segment_owner,  
                          segment_name              => p_segment_name,  
                          segment_type              => p_segment_type,  
                          total_blocks              => l_total_blocks,  
                          total_bytes               => l_total_bytes,  
                          unused_blocks             => l_unused_blocks,  
                          unused_bytes              => l_unused_bytes,  
                          last_used_extent_file_id  => l_lastusedextfileid,  
                          last_used_extent_block_id => l_lastusedextblockid,  
                          last_used_block           => l_last_used_block,  
                          partition_name            => p_partition_name);  
  p('Total Blocks  ', l_total_blocks);  
  p('Total Bytes   ', l_total_bytes);  
  p('Total MBytes  ', l_total_bytes / 1024 / 1024);  
  p('Unused Blocks ', l_unused_blocks);  
  p('Unused Bytes  ', l_unused_bytes);  
  p('Unused KBytes ', l_unused_bytes / 1024);  
  p('Used Blocks   ', l_total_blocks - l_unused_blocks);  
  p('Used Bytes    ', l_total_bytes - l_unused_bytes);  
  p('Used KBytes   ', (l_total_bytes - l_unused_bytes) / 1024);  
  p('Last Used Ext FileId', l_lastusedextfileid);  
  p('Last Used Ext BlockId', l_lastusedextblockid);  
  p('Last Used Block', l_last_used_block);  
  
  if p_analyzed = 'Y' then  
    if p_space = 'AUTO' then  
      dbms_space.space_usage(segment_owner      => p_segment_owner,  
                             segment_name       => p_segment_name,  
                             segment_type       => p_segment_type,  
                             unformatted_blocks => l_unformatted_blocks,  
                             unformatted_bytes  => l_unformatted_bytes,  
                             fs1_blocks         => l_fs1_blocks,  
                             fs1_bytes          => l_fs1_bytes,  
                             fs2_blocks         => l_fs2_blocks,  
                             fs2_bytes          => l_fs2_bytes,  
                             fs3_blocks         => l_fs3_blocks,  
                             fs3_bytes          => l_fs3_bytes,  
                             fs4_blocks         => l_fs4_blocks,  
                             fs4_bytes          => l_fs4_bytes,  
                             full_blocks        => l_full_blocks,  
                             full_bytes         => l_full_bytes,  
                             partition_name     => p_partition_name);  
      
      dbms_output.put_line('');  
      dbms_output.put_line('The segment is analyzed below');  
      p('FS1 Blocks (0-25)   ', l_fs1_blocks);  
      p('FS2 Blocks (25-50)  ', l_fs2_blocks);  
      p('FS3 Blocks (50-75)  ', l_fs3_blocks);  
      p('FS4 Blocks (75-100) ', l_fs4_blocks);  
      p('Unformatted Blocks  ', l_unformatted_blocks);  
      p('Full Blocks         ', l_full_blocks);  
    else  
      dbms_space.free_blocks(segment_owner     => p_segment_owner,  
                             segment_name      => p_segment_name,  
                             segment_type      => p_segment_type,  
                             freelist_group_id => 0,  
                             free_blks         => l_free_blks);  
      p('Free Blocks', l_free_blks);  
    end if;  
  end if;  
end;  



一. 测试准备
select count(*) from MESSAGEIN;
--978619


SQL> desc MESSAGEIN
 Name					   Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID					   NOT NULL NUMBER
 MSGID						    VARCHAR2(100)
 STATUS 					    NUMBER
 PROCCNT					    NUMBER
 ACCEPTTIME					    TIMESTAMP(6)
 MSGBODY					    CLOB
 QUEUE						    VARCHAR2(20)


SQL> select max(accepttime),min(accepttime) from MESSAGEIN;

MAX(ACCEPTTIME)
---------------------------------------------------------------------------
MIN(ACCEPTTIME)
---------------------------------------------------------------------------
20-OCT-13 08.52.00.461000 PM
25-JUN-10 05.01.55.745000 PM

SQL> select segment_name,bytes/1024/1024 from user_segments where segment_name in (
select TABLE_NAME from user_lobs where table_name='MESSAGEIN'
union all select SEGMENT_NAME  from user_lobs where table_name='MESSAGEIN'
union all select index_name from user_lobs where table_name='MESSAGEIN')  2    3    4  
  5  ;

SEGMENT_NAME		       BYTES/1024/1024
------------------------------ ---------------
MESSAGEIN				  1280
SYS_IL0000209895C00006$$		    14
SYS_LOB0000209895C00006$$		  4335



SQL> set serveroutput on
SQL>  exec show_space('MESSAGEIN','MBFE','TABLE');
Total Blocks  ..........................163840
Total Bytes   ..........................1342177280
Total MBytes  ..........................1280
Unused Blocks ..........................1711
Unused Bytes  ..........................14016512
Unused KBytes ..........................13688
Used Blocks   ..........................162129
Used Bytes    ..........................1328160768
Used KBytes   ..........................1297032
Last Used Ext FileId....................36
Last Used Ext BlockId...................155904
Last Used Block.........................6481
The segment is analyzed below
FS1 Blocks (0-25)   ....................0
FS2 Blocks (25-50)  ....................0
FS3 Blocks (50-75)  ....................0
FS4 Blocks (75-100) ....................0
Unformatted Blocks  ....................0
Full Blocks	    ....................161607

PL/SQL procedure successfully completed.


二.清理数据
DECLARE
  CURSOR cur IS
select rowid as ROW_ID from MESSAGEIN a
where accepttime <= date'2012-12-31'
order by rowid; 
  V_COUNTER NUMBER;
BEGIN
  V_COUNTER := 0;
  FOR row IN cur LOOP
delete from MESSAGEIN 
     WHERE ROWID = row.ROW_ID;
    V_COUNTER := V_COUNTER + 1;
    IF (V_COUNTER >= 1000) THEN
      COMMIT;
      V_COUNTER := 0;
    END IF;
  END LOOP;
  COMMIT;
END;

三:对比结果
SQL> select count(*) from MESSAGEIN;

  COUNT(*)
----------
    206887

SQL> select max(accepttime),min(accepttime) from MESSAGEIN;


MAX(ACCEPTTIME)
---------------------------------------------------------------------------
MIN(ACCEPTTIME)
---------------------------------------------------------------------------
20-OCT-13 08.52.00.461000 PM
31-DEC-12 07.57.41.941000 AM



SQL> set serveroutput on
SQL> exec show_space('MESSAGEIN','MBFE','TABLE');
Total Blocks  ..........................163840
Total Bytes   ..........................1342177280
Total MBytes  ..........................1280
Unused Blocks ..........................1711
Unused Bytes  ..........................14016512
Unused KBytes ..........................13688
Used Blocks   ..........................162129
Used Bytes    ..........................1328160768
Used KBytes   ..........................1297032
Last Used Ext FileId....................36
Last Used Ext BlockId...................155904
Last Used Block.........................6481
The segment is analyzed below
FS1 Blocks (0-25)   ....................0
FS2 Blocks (25-50)  ....................67
FS3 Blocks (50-75)  ....................163
FS4 Blocks (75-100) ....................127808
Unformatted Blocks  ....................0
Full Blocks	    ....................33569

PL/SQL procedure successfully completed.




SQL> select segment_name,bytes/1024/1024 from user_segments where segment_name in (
select TABLE_NAME from user_lobs where table_name='MESSAGEIN'
union all select SEGMENT_NAME  from user_lobs where table_name='MESSAGEIN'
union all select index_name from user_lobs where table_name='MESSAGEIN')   2    3    4  ;

SEGMENT_NAME									  BYTES/1024/1024
--------------------------------------------------------------------------------- ---------------
MESSAGEIN										     1280
SYS_IL0000209895C00006$$								       32
SYS_LOB0000209895C00006$$								     4335

表和lob字段的空间没释放:



四 开始清理:

SQL> select index_name,status from user_indexes where table_name='MESSAGEIN';

INDEX_NAME		       STATUS
------------------------------ --------
SYS_IL0000209895C00006$$       VALID
MESSAGEIN_PK		       VALID
INDEXMSGIN_1		       VALID


SQL> alter table MESSAGEIN move;

Table altered.

SQL> select index_name,status from user_indexes where table_name='MESSAGEIN';

INDEX_NAME		       STATUS
------------------------------ --------
SYS_IL0000209895C00006$$       VALID
MESSAGEIN_PK		       UNUSABLE
INDEXMSGIN_1		       UNUSABLE

索引失效 需要重建索引:
SQL> set serveroutput on
SQL> exec show_space('MESSAGEIN','MBFE','TABLE');
Total Blocks  ..........................163840
Total Bytes   ..........................1342177280
Total MBytes  ..........................1280
Unused Blocks ..........................129961
Unused Bytes  ..........................1064640512
Unused KBytes ..........................1039688
Used Blocks   ..........................33879
Used Bytes    ..........................277536768
Used KBytes   ..........................271032
Last Used Ext FileId....................36
Last Used Ext BlockId...................1467520
Last Used Block.........................1111
The segment is analyzed below
FS1 Blocks (0-25)   ....................0
FS2 Blocks (25-50)  ....................0
FS3 Blocks (50-75)  ....................0
FS4 Blocks (75-100) ....................0
Unformatted Blocks  ....................0
Full Blocks	    ....................33717

PL/SQL procedure successfully completed.



move 后 数据块回收:


同时清理Lob字段:
SQL> alter table MESSAGEIN modify lob(MSGBODY) (shrink space);

Table altered.

SQL> select segment_name,bytes/1024/1024 from user_segments where segment_name in (
select TABLE_NAME from user_lobs where table_name='MESSAGEIN'
union all select SEGMENT_NAME  from user_lobs where table_name='MESSAGEIN'
union all select index_name from user_lobs where table_name='MESSAGEIN')  2    3    4  ;

SEGMENT_NAME									  BYTES/1024/1024
--------------------------------------------------------------------------------- ---------------
MESSAGEIN										     1280
SYS_IL0000209895C00006$$								       32
SYS_LOB0000209895C00006$$								  952.625

此时lob空间回收


重建索引:


SQL>  alter index MESSAGEIN_PK  rebuild online;

Index altered.

SQL>  alter index INDEXMSGIN_1 rebuild online;

Index altered.

SQL> select index_name,status from user_indexes where table_name='MESSAGEIN';

INDEX_NAME		       STATUS
------------------------------ --------
SYS_IL0000209895C00006$$       VALID
MESSAGEIN_PK		       VALID
INDEXMSGIN_1		       VALID

原文地址:https://www.cnblogs.com/hzcya1995/p/13351813.html