-- #############################################################################################
--
-- %Purpose: How to reclaim UNUSED_SPACE from Indexes and Tables using DBMS_SPACE.UNUSED_SPACE
--
-- Before growing a datafile in a tablespace that shows on your
-- space analysis reports, search for space that can be reclaimed
-- from an object that was poorly sized initially. Tables and indexes
-- can be altered with a deallocate unused, thus reclaiming unused
-- space above the high-water mark.
--
-- Example: ALTER TABLE emp DEALLOCATE UNUSED;
--
-- This script prompts you for two pieces of information:
--
-- 1. The type of segment to retrieve, (i=indexes, t=tables)
--
-- 2. The tablespace_name to retrieve from.
--
-- Simply put, this allows you to retrieve one of these segment
-- types by tablespace_name. It is important to note that deallocating
-- unused space became available with Oracle version 7.3.
--
-- #############################################################################################--
--
accept type prompt "Enter the type of segment to check (i=index, t=table): "
accept ts_name prompt "Enter the tablespace name that you wish to check: "
set serveroutput on
feedback off
--
spool unused_space.lst
--
DECLARE
  v_total_blocks   NUMBER;
  v_total_bytes    NUMBER;
  v_unused_blocks  NUMBER;
  v_unused_bytes   NUMBER;
  v_file_id        NUMBER;
  v_block_id       NUMBER;
  v_last_block     NUMBER;
  v_used           NUMBER;
  v_owner          VARCHAR2(12);
  v_segment        VARCHAR2(80);
  v_type           CHAR(1);

  CURSOR index_c is
  SELECT owner, index_name
    FROM sys.dba_indexes
   WHERE tablespace_name = upper('&ts_name');

  CURSOR table_c is
  SELECT owner, table_name
    FROM sys.dba_tables
   WHERE tablespace_name = upper('&ts_name');

BEGIN
  DBMS_OUTPUT.ENABLE(100000);
  v_type := '&type';
  IF (v_type = 'i' or v_type = 'I') THEN
     OPEN index_c;
     FETCH index_c into v_owner, v_segment;
     WHILE index_c%FOUND LOOP
           --
           DBMS_SPACE.UNUSED_SPACE(v_owner, v_segment, 'INDEX', v_total_blocks, v_total_bytes,
                                   v_unused_blocks, v_unused_bytes, v_file_id, v_block_id, v_last_block);
           --
           DBMS_OUTPUT.PUT_LINE(CHR(10));
           DBMS_OUTPUT.PUT_LINE('Index Name                   = '||v_segment);
           DBMS_OUTPUT.PUT_LINE('Total Blocks                 = '||v_total_blocks);
           DBMS_OUTPUT.PUT_LINE('Total Bytes                  = '||v_total_bytes);
           DBMS_OUTPUT.PUT_LINE('Unused Blocks                = '||v_unused_blocks);
           DBMS_OUTPUT.PUT_LINE('Unused Bytes                 = '||v_unused_bytes);
           v_used := v_total_blocks - v_unused_blocks;
           DBMS_OUTPUT.PUT_LINE('Used Blocks                  = '||v_used);
           v_used := v_total_bytes - v_unused_bytes;
           DBMS_OUTPUT.PUT_LINE('Used Bytes                   = '||v_used);
           DBMS_OUTPUT.PUT_LINE('Last used extents file id    = '||v_file_id);
           DBMS_OUTPUT.PUT_LINE('Last used extents block id   = '||v_block_id);
           DBMS_OUTPUT.PUT_LINE('Last used block              = '||v_last_block);
           fetch index_c into v_owner, v_segment;
      END LOOP;
      CLOSE index_c;
  ELSIF (v_type = 't' or v_type = 'T') THEN
    OPEN table_c;
        FETCH table_c into v_owner, v_segment;
        WHILE table_c%FOUND LOOP
            --
            DBMS_SPACE.UNUSED_SPACE(v_owner, v_segment, 'TABLE', v_total_blocks, v_total_bytes,
                                    v_unused_blocks, v_unused_bytes, v_file_id, v_block_id, v_last_block);
            --
            v_used := v_total_bytes - v_unused_bytes;
            DBMS_OUTPUT.PUT_LINE(CHR(10));
            DBMS_OUTPUT.PUT_LINE('Table Name                   = '||v_segment);
            DBMS_OUTPUT.PUT_LINE('Total Blocks                 = '||v_total_blocks);
            DBMS_OUTPUT.PUT_LINE('Total Bytes                  = '||v_total_bytes);
            DBMS_OUTPUT.PUT_LINE('Unused Blocks                = '||v_unused_blocks);
            DBMS_OUTPUT.PUT_LINE('Unused Bytes                 = '||v_unused_bytes);
            v_used := v_total_blocks - v_unused_blocks;
            DBMS_OUTPUT.PUT_LINE('Used Blocks                  = '||v_used);
            v_used := v_total_bytes - v_unused_bytes;
            DBMS_OUTPUT.PUT_LINE('Used Bytes                   = '||v_used);
            DBMS_OUTPUT.PUT_LINE('.    KBytes                  = '||v_used/1024);
            DBMS_OUTPUT.PUT_LINE('.    MBytes                  = '||(v_used/1024)/1024);
            DBMS_OUTPUT.PUT_LINE('Last used extents file id    = '||v_file_id);
            DBMS_OUTPUT.PUT_LINE('Last used extents block id   = '||v_block_id);
            DBMS_OUTPUT.PUT_LINE('Last used block              = '||v_last_block);
            fetch table_c into v_owner, v_segment;
      END LOOP;
      CLOSE table_c;
  END IF;
END;
/
spool off
