myorama
8/1/2016 - 1:09 PM

Reporting space-wasting objects in Oracle Source https://www.pythian.com/blog/reporting-space-wasting-objects-in-oracle/

Reporting space-wasting objects in Oracle Source https://www.pythian.com/blog/reporting-space-wasting-objects-in-oracle/

connect &your_account/&your_account_password
 
create table segment_space_stats
       (owner                     varchar2(32),
        segment_name              varchar2(32),
        segment_type              varchar2(32),
        tablespace_name           varchar2(32),
        segment_space_management  varchar2(32),
        unformatted_blocks        number,
        unformatted_bytes         number,
        fs1_blocks                number,
        fs1_bytes                 number,
        fs2_blocks                number,
        fs2_bytes                 number,
        fs3_blocks                number,
        fs3_bytes                 number,
        fs4_blocks                number,
        fs4_bytes                 number,
        full_blocks               number,
        full_bytes                number,
        total_blocks              number,
        total_bytes               number,
        unused_blocks             number,
        unused_bytes              number,
        last_used_extent_file_id  number,
        last_used_extent_block_id number,
        last_used_block           number,
        timestamp                 date)
;
-- You may need to grant these to your_account.
--
-- connect sys as sysdba
-- grant select any tables, select any dictionary, analyze any to &your_account;
-- grant execute on dbms_space to &your_account;
-- connect &your_account/&your_account_password
 
CREATE OR REPLACE PROCEDURE GEN_SEGMENT_SPACE_STATS 
AS
  index_does_not_exist EXCEPTION;
  table_does_not_exist EXCEPTION;
  PRAGMA EXCEPTION_INIT(index_does_not_exist, -1418);
  PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);

  v_unformatted_blocks number;
  v_unformatted_bytes  number;
  v_fs1_blocks         number;
  v_fs1_bytes          number;
  v_fs2_blocks         number;
  v_fs2_bytes          number;
  v_fs3_blocks         number;
  v_fs3_bytes          number;
  v_fs4_blocks         number;
  v_fs4_bytes          number;
  v_full_blocks        number;
  v_full_bytes         number;

  v_total_blocks number;
  v_total_bytes number;
  v_unused_blocks number;
  v_unused_bytes number;
  v_last_used_extent_file_id number;
  v_last_used_extent_block_id number;
  v_last_used_block number;

BEGIN
  for s in (select owner, segment_name, replace(segment_type,'LOBSEGMENT','LOB') segment_type, seg.tablespace_name, segment_space_management
              from dba_tablespaces ts, dba_segments seg
             where ts.tablespace_name not in ('SYSTEM', 'SYSAUX')
               and ts.tablespace_name = seg.tablespace_name
               and segment_type in ('TABLE','INDEX','CLUSTER','LOB','LOBSEGMENT'))
  loop
    begin

      if s.segment_space_management = 'AUTO' then
         dbms_space.space_usage(s.owner, s.segment_name, s.segment_type, v_unformatted_blocks, v_unformatted_bytes,
                                v_fs1_blocks, v_fs1_bytes, v_fs2_blocks, v_fs2_bytes , v_fs3_blocks, v_fs3_bytes ,
                                v_fs4_blocks, v_fs4_bytes , v_full_blocks, v_full_bytes , NULL);
      end if;
      dbms_space.unused_space(s.owner, s.segment_name, s.segment_type, v_total_blocks, v_total_bytes,
                              v_unused_blocks, v_unused_bytes, v_last_used_extent_file_id,
                              v_last_used_extent_block_id, v_last_used_block, NULL);
                              
      merge into segment_space_stats r
           using (select s.owner as owner, s.segment_name as segment_name, s.segment_type as segment_type from dual) t
              on (r.owner = t.owner and r.segment_name = t.segment_name and r.segment_type = t.segment_type)
            when matched then update
             set r.tablespace_name = s.tablespace_name, r.unformatted_blocks = v_unformatted_blocks,
                 r.unformatted_bytes = v_unformatted_bytes, r.fs1_blocks = v_fs1_blocks, r.fs1_bytes = v_fs1_bytes,
                 r.fs2_blocks = v_fs2_blocks, r.fs2_bytes = v_fs2_bytes, r.fs3_blocks = v_fs3_blocks,
                 r.fs3_bytes = v_fs3_bytes, r.fs4_blocks = v_fs4_blocks, r.fs4_bytes = v_fs4_bytes,
                 r.full_blocks = v_full_blocks, r.full_bytes = v_full_bytes, r.total_blocks = v_total_blocks,
                 r.total_bytes = v_total_bytes, r.unused_blocks = v_unused_blocks, r.unused_bytes = v_unused_bytes,
                 r.last_used_extent_file_id = v_last_used_extent_file_id, r.last_used_extent_block_id =v_last_used_extent_block_id,
                 r.last_used_block = v_last_used_block, r.timestamp = sysdate
            when not matched then insert
          values (s.owner, s.segment_name, s.segment_type, s.tablespace_name, s.segment_space_management,v_unformatted_blocks,
                  v_unformatted_bytes, v_fs1_blocks, v_fs1_bytes, v_fs2_blocks, v_fs2_bytes, v_fs3_blocks, v_fs3_bytes,
                  v_fs4_blocks, v_fs4_bytes, v_full_blocks, v_full_bytes, v_total_blocks, v_total_bytes,
                  v_unused_blocks, v_unused_bytes, v_last_used_extent_file_id, v_last_used_extent_block_id,
                  v_last_used_block,sysdate);
         
    exception
      when index_does_not_exist then
        null; -- ignore these errors
      when table_does_not_exist then
        null; -- ignore these errors
      when others then
        raise;
    end;
  end loop;
  commit;

  delete segment_space_stats where (owner, segment_name, segment_type, tablespace_name) not in
  (select owner, segment_name, replace(segment_type,'LOBSEGMENT','LOB'), tablespace_name from dba_segments
    where tablespace_name not in ('SYSTEM', 'SYSAUX')
      and segment_type in ('TABLE','INDEX','CLUSTER','LOB','LOBSEGMENT'));
  commit;
END;
/
TTITLE center underline "Top Ten Largest Space Wasters"
set linesize 140 pagesize 20
col owner for a20
col segment_type for a12
col total_MB for 999999
col unformatted_MB for 999999
col unused_MB for 999999
col pct_unused for 999 heading "Pct Unused"
col estmtd_pssbl_svngs for 99999 heading "Estimated|Possible Savings|w Index Rebuild"
clear breaks
clear computes
break on report dup
compute sum of total_MB on report
compute sum of unused_MB on report
 
select a.*
  from (
        select owner, segment_name, segment_type,
               total_bytes/1048576 total_MB,
               unformatted_bytes/1048576 unformatted_MB,
               unused_bytes/1048576 unused_MB,
               trunc(unused_bytes / total_bytes * 100) pct_unused,
               case when segment_type = 'INDEX' and total_blocks >= 256 and fs2_blocks >= 64
                         then unused_blocks + fs2_blocks
                    else 0
               end * b.block_size/1048576 estmtd_pssbl_svngs
          from segment_space_stats a, dba_tablespaces b
         where unused_bytes <> 0
           and a.tablespace_name = b.tablespace_name
         order by unused_bytes desc) a
where rownum<11
;
TTITLE center underline "Top Ten Indexes with non-full blocks"
clear breaks
clear computes
set linesize 145 pagesize 100
col owner for a20
col fs1_blocks for 9999999 heading "< 25%|blocks free"
col fs2_blocks for 9999999 heading "25-50%|blocks free"
col fs3_blocks for 9999999 heading "50-75%|blocks free"
col fs4_blocks for 9999999 heading "75-100%|blocks free"
col full_blocks for 9999999 heading "blocks|full"
col total_blocks for 9999999 heading "total|blocks"
col estmtd_pssbl_svngs for 99999 heading "Estimated|Possible Savings|w Index Rebuild"
col block_size noprint
break on report dup
compute sum of estmtd_pssbl_svngs on report
select a.*
  from (
        select owner, segment_name,
               fs1_blocks ,
               fs2_blocks ,
               fs3_blocks ,
               fs4_blocks ,
               full_blocks, total_blocks,
               case when segment_type = 'INDEX' and total_blocks >= 256 and fs2_blocks >= 64
                         then unused_blocks + fs2_blocks
                    else 0
               end * b.block_size/1048576 estmtd_pssbl_svngs,
               b.block_size
          from segment_space_stats a, dba_tablespaces b
         where segment_type = 'INDEX'
           and a.tablespace_name = b.tablespace_name
         order by fs4_blocks desc, fs3_blocks desc, fs2_blocks desc, fs1_blocks desc) a
where rownum<11
;
TTITLE center underline "Top Ten Largest Empty Segments"
set linesize 140 pagesize 100
col owner for a20
col total_MB for 999999
clear breaks
clear computes
break on report dup
compute sum of total_MB on report
select a.*
  from (select owner, segment_name, segment_type, tablespace_name, total_bytes/1048576 total_MB
          from segment_space_stats
         where full_bytes = 0
        order by total_bytes desc) a
where rownum<11
;