Hi guys, below is test case to determine if we have some fragmented object
## Step 1 ##
i'm creating the table and the index also (later for deleting purpose)
===============================================
SQL> select /*+ full(a) parallel(a,8) */ count(*) from TESTAB a;
COUNT(*)
----------
5247350
SQL> create unique index TESTAB_pk on TESTAB(ACCOUNT_ID);
Index created.
below is the estimate space before we gather the stat
=====================================================
SQL> select table_name, round((blocks*8)/1024,2) tblsz_frgmnted_MB, round((NUM_ROWS*avg_row_len/1024/1024),2) actualsize_MB
2 from dba_tables where table_name='TESTAB'
3 and owner in ('TESUSER') ;
TABLE_NAME TBLSZ_FRGMNTED_MB ACTUALSIZE_MB
------------- ----------------- -------------
TESTAB
SQL> select owner, segment_name , sum(bytes/1024/1024) as MB
2 from dba_segments
3 where segment_name='TESTAB'
4 and owner in ('TESUSER') group by owner, segment_name;
OWNER SEGMENT_NAME MB
------------- -------------------- ----------
TESUSER TESTAB 872
## Step 2 ##
Gather the stat for the table
=============================
SQL> exec DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'TESUSER', TABNAME => 'TESTAB', METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE 2', DEGREE => 12,CASCADE => TRUE,estimate_percent => 5);
PL/SQL procedure successfully completed.
SQL> select table_name, round((blocks*8)/1024,2) tblsz_frgmnted_MB, round((NUM_ROWS*avg_row_len/1024/1024),2) actualsize_MB
from dba_tables where table_name='TESTAB'
and owner in ('TESUSER') ; 2 3
TABLE_NAME TBLSZ_FRGMNTED_MB ACTUALSIZE_MB
----------------- ----------------- -------------
TESTAB 866.88 725.71
SQL> select owner, segment_name , sum(bytes/1024/1024) as MB
from dba_segments
where segment_name='TESTAB'
and owner in ('TESUSER') group by owner, segment_name; 2 3 4
OWNER SEGMENT_NAME MB
-------------- ---------------- ----------
TESUSER TESTAB 872
## Step 3 ##
==============================================
deleting tables to produce the fragmented space
==============================================
SQL> create table TESTAB_accid as select ACCOUNT_ID from TESTAB where rownum < = 2000000;
SQL> delete from TESTAB
where ACCOUNT_ID in ( select ACCOUNT_ID from TESTAB_accid );
=================
Gather stat again
=================
SQL> exec DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'TESUSER', TABNAME => 'TESTAB', METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE 2', DEGREE => 12,CASCADE => TRUE,estimate_percent => 10);
PL/SQL procedure successfully completed.
SQL> select table_name, round((blocks*8)/1024,2) tblsz_frgmnted_MB, round((NUM_ROWS*avg_row_len/1024/1024),2) actualsize_MB
from dba_tables where table_name='TESTAB'
and owner in ('TESUSER') ; 2 3
TABLE_NAME TBLSZ_FRGMNTED_MB ACTUALSIZE_MB
------------------------------ ----------------- -------------
TESTAB 866.88 445.96
SQL> select owner, segment_name , sum(bytes/1024/1024) as MB
2 from dba_segments
3 where segment_name='TESTAB'
4 and owner in ('TESUSER') group by owner, segment_name;
OWNER SEGMENT_NAME MB
------------- ------------ --------
TESUSER TESTAB 872
## Step 3 ##
==============================================
Defrag table and don't forget to rebuild index
==============================================
SQL> alter table TESTAB move tablespace datal01;
Table altered.
SQL> alter index TESTAB_PK rebuild;
Index altered.
SQL> exec DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'TESUSER', TABNAME => 'TESTAB', METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE 2', DEGREE => 12,CASCADE => TRUE,estimate_percent => 10);
PL/SQL procedure successfully completed.
SQL> select table_name, round((blocks*8)/1024,2) tblsz_frgmnted_MB, round((NUM_ROWS*avg_row_len/1024/1024),2) actualsize_MB
from dba_tables where table_name='TESTAB'
and owner in ('TESUSER') ; 2 3
as shown below the gap still there because of from the actual size dont include for some percentage each block reserve for header, dict, etc
TABLE_NAME TBLSZ_FRGMNTED_MB ACTUALSIZE_MB
------------------------------ ----------------- -------------
TESTAB 531.92 447.49
SQL>
SQL> select owner, segment_name , sum(bytes/1024/1024) as MB
from dba_segments
where segment_name='TESTAB'
and owner in ('TESUSER') group by owner, segment_name; 2 3 4
OWNER SEGMENT_NAME MB
----------- -------------- ----------
TESUSER TESTAB 536