Skip to main content

ORACLE DBA - Get segment size, compare table and index size

Creating simple function we can get table`s size.

CREATE OR REPLACE FUNCTION ULFET.CHECK_TABLE_SIZE(TAB_NAME VARCHAR) RETURN varchar
IS
   tab_size number;
   str varchar2(50);
BEGIN  
     SELECT  SUM (bytes) / (1024 * 1024)  INTO tab_size
     FROM sys.dba_extents WHERE segment_type = 'TABLE' AND segment_name = TAB_NAME GROUP BY segment_name;
str := tab_name||' size is '||tab_size||' MB';
RETURN str;
END;
/

P.S: If compilation will error grant select on sys.dba_extents to desired user and repeat creation.

SQL> conn /as sysdba

SQL> grant select on sys.dba_extents to ulfet;

Grant succeeded.

SQL>



--call
select ULFET.CHECK_TABLE_SIZE('TEST_TAB') from dual;

or

set serveroutput on
declare
l_answvarchar2(100);
begin
l_answ:=ULFET.CHECK_TABLE_SIZE('TEST_TAB');
dbms_output.put_line(l_answ);
end;
select ULFET.CHECK_TABLE_SIZE('TEST_TAB') from dual;

P.S: Please note that table_name should be entered with upper case.

Above function will return for tables which gathered statistic.
To get statistics you can use several methods : ANALYZE or DBMS_STATS.GATHER_TABLE_STATS

Example:


exec ANALYZE TABLE employees COMPUTE STATISTICS; --it computes actual statistics
exec ANALYZE TABLE employees ESTIMATE STATISTICS; --estimates the stats
exec DBMS_STATS.GATHER_TABLE_STATS ('HR','EMPLOYEES');


DBMS_STATS package available on Oracle 10g and later versions.

Sometimes we getting request something like that, is it possible index size bigger than table`s size?
Yes, possible, let`s simulate.

SQL> create table test_tbl (id number, col1 varchar2(2000));

Table created.

SQL> create index idx_test_tbl on test_tbl(col1);

Index created.

SQL> begin
        for i in 1..10000 loop
                insert into test_tbl values (i, lpad(i,2000, 'z'));
        end loop;
        commit;
end;
/  2    3    4    5    6    7

PL/SQL procedure successfully completed.


SQL> delete from test_tbl;

10000 rows deleted.

SQL> commit;



Check table and index`s size


SQL> col segment_name format a20
SQL> SELECT segment_name, SUM (bytes) / (1024 * 1024) size_mb
FROM sys.dba_extents
WHERE segment_type in('TABLE','INDEX')
AND segment_name in('TEST_TBL', 'IDX_TEST_TBL') and owner='ULFET'
group by segment_name;

SEGMENT_NAME            SIZE_MB
--------------------              ----------
TEST_TBL                          27
IDX_TEST_TBL                 46

SQL>

SQL> with tabs as (select segment_name tablename,bytes tablesize from user_segments where segment_type='TABLE'),
inds as (select i.index_name indexname,i.table_name tablename,s.bytes indexsize from user_indexes i join user_segments s on (i.index_name=s.segment_name))
select * from tabs natural join inds where indexsize > tablesize;  2    3  


 TABLENAME    TABLESIZE  INDEXNAME     INDEXSIZE  
 ---------    ---------  ------------  ---------  
 TEST_TBL     28311552   IDX_TEST_TBL  48234496  
 SQL> 

List of indexes which size bigger than tables


SQL> col tablename format a23
SQL> WITH tabs AS (SELECT segment_name tablename, bytes tablesize FROM dba_segments

  WHERE segment_type = 'TABLE' AND owner NOT IN ('SYS', 'SYSTEM', 'SYSMAN', 'PUBLIC')),
        inds AS (SELECT i.index_name indexname, i.table_name tablename, s.bytes indexsize FROM dba_indexes i  JOIN dba_segments s ON (i.index_name = s.segment_name)
AND s.owner NOT IN ('SYS', 'SYSTEM', 'SYSMAN', 'PUBLIC')
)
SELECT * FROM tabs NATURAL JOIN inds WHERE indexsize > tablesize;



For performance it is good to check table`s which size more than 2 GB and not partitioned.

Get list of tables which size more than 2 GB and not partitioned.

SELECT A.OWNER,
       A.SEGMENT_NAME,
       BYTES,
       ROUND (BYTES / 1024 / 1024 / 1024, 2) SIZE_GB,
       B.OBJECT_TYPE,
       PARTITIONED
  FROM DBA_SEGMENTS A, DBA_OBJECTS B, DBA_TABLES C
 WHERE     A.SEGMENT_NAME = B.OBJECT_NAME
       AND A.OWNER NOT IN ('SYS', 'SYSTEM')
       AND BYTES > 2147483648
       AND OBJECT_TYPE = 'TABLE'
       AND C.TABLE_NAME = A.SEGMENT_NAME
       --AND PARTITIONED = 'YES'
       ORDER by size_gb,  segment_name


Comments

  1. when index size>table size. how to fix this issue. It is a prod db. Is there any impact to db?
    Can you pl reply

    ReplyDelete
  2. Hello Krish. First of all I think you must check index statistic is stale ? Check also extents count for index. You may shrink index
    ALTER INDEX testidx SHRINK SPACE COMPACT;
    Also move to another tablespace (it will effect extent count - reduce)
    Is you index compact (used more than one column) ?
    Please share here your result of query:

    SELECT segment_name, SUM (bytes) / (1024 * 1024) size_mb
    FROM sys.dba_extents
    WHERE segment_type in('TABLE','INDEX')
    AND segment_name in('YOUTTABLE', 'YOURINDEX') and owner='YOURNEEDEDUSER'
    group by segment_name;

    ReplyDelete

Post a Comment

Popular posts from this blog

Fix ORA-01139: RESETLOGS option only valid after an incomplete database recovery

While shutting down my TEST database process was hanged. Then I had to use shutdown abort. But when I wanted to start database it did not open. SQL> select name from v$database; NAME --------- TEST SQL> shut abort; ORACLE instance shut down. SQL> startup mount ORACLE instance started. Total System Global Area 6597406720 bytes Fixed Size 2265664 bytes Variable Size 3204451776 bytes Database Buffers 3372220416 bytes Redo Buffers 18468864 bytes Database mounted. SQL> alter database open; alter database open * ERROR at line 1: ORA-03113: end-of-file on communication channel Process ID: 6552 Session ID: 191 Serial number: 3  What`s wrong?  SQL> alter database open resetlogs; ERROR:    ORA-03114: not connected to ORACLE    SQL> exit Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Pr...

Fix: ORA-13639: The current operation was interrupted because it timed out.

Sometimes SQL Tuning Advisor interrupts cause time limit took more than defined. You have to analyze it or increase value. Here you can see increasing of value. Example result of sql select                  execution_name, advisor_name,                  to_char(execution_start,'dd-mon-yy hh:mi:ss') execution_start,                  to_char(execution_end,'dd-mon-yy hh:mi:ss') execution_end, status,error_message from dba_advisor_executions where task_name = 'SYS_AUTO_SQL_TUNING_TASK' order by execution_start; Check value of TIME_LIMIT`s parameter : SQL> column parameter_value for A35 SQL> select parameter_name, parameter_value from dba_advisor_parameters where task_name = 'SYS_AUTO_SQL_TUNING_TASK' and parameter_name in ('TIME_LIMIT', 'DEFAULT_EXECUTION_TYP...

How to fix ORA-26040: Data block was loaded using the NOLOGGING option

Today I faced with new ORA error. After solving I want to share this experience with yours. So, today 5`th datafile of my database was corrupted (/u01/app/oracle/oradata/ulfet_db/example01.dbf). After recover via RMAN I saw strange error. RMAN> recover datafile 5 block 443; Starting recover at 24-MAR-13 using channel ORA_DISK_1 channel ORA_DISK_1: restoring block(s) channel ORA_DISK_1: specifying block(s) to restore from backup set restoring blocks of datafile 00005 channel ORA_DISK_1: reading from backup piece /u01/app/oracle/flash_recovery_area/ULFET_DB/backupset/2013_03_24/o1_mf_nnndf_TAG20130324T223233_8nykp220_.bkp channel ORA_DISK_1: piece handle=/u01/app/oracle/flash_recovery_area/ULFET_DB/backupset/2013_03_24/o1_mf_nnndf_TAG20130324T223233_8nykp220_.bkp tag=TAG20130324T223233 channel ORA_DISK_1: restored block(s) from backup piece 1 channel ORA_DISK_1: block restore complete, elapsed time: 00:00:03 starting media recovery media recovery complete, elapsed ti...