Wikipedia

Search results

Auditing DDL changes

Auditing changes within the database are becoming more and more important. As well as auditing changes to data, auditing DDL changes can be just as critical. This allows the DBA to not only know what changes have been made but also what haven’t. Being able to see what changes have been made to the database can make debugging much quicker.

This solution consists of two tables, one sequence and one trigger.
 
The Tables and Sequence

CREATE TABLE ddl_events
( eventId          NUMBER(10,0),
  eventDate        DATE,
  oraLoginUser     VARCHAR2(30),
  oraDictObjName   VARCHAR2(30),
  oraDictObjOwner  VARCHAR2(30),
  oraDictObjType   VARCHAR2(30),
  oraSysEvent      VARCHAR2(30),
  machine          VARCHAR2(64),
  program          VARCHAR2(64),
  osuser           VARCHAR2(30) );

CREATE TABLE ddl_events_sql
( eventId          NUMBER(10,0),
  sqlLine          NUMBER(10,0),
  sqlText          VARCHAR2(4000) );

CREATE SEQUENCE dsq_ddlEvents START WITH 1000; 
The parent table ddl_events stores data about the DDL event
•    eventId : Unique key generated by the sequence.
•    eventDate : Populated with SYSDATE.
•    oraLoginUser : The login username taken from the ORA_LOGIN_USER function.
•    oraDictObjName : The name of the event object taken from the ORA_DICT_OBJ_NAME function.
•    oraDictObjOwner : The owner of the event object taken from the ORA_DICT_OBJ_OWNER function.
•    oraDictObjType : The type of the event object taken from the ORA_DICT_OBJ_TYPE function.
•    oraSysEvent : The type of event, EG Create, Alter, Delete. Taken from the ORA_SYS_EVENT function.
•    machine : The name of the machine the event was issued from. Taken from v_$session.
•    program : The name of the program use to issue the command. Taken from v_$session.
•    osuser : The operating system user name. Taken from v_$session.

The ddl_events_sql table stores the sql text from the command. This is a child table of ddl_events with the eventId being the foreign key. EventId and sqlLine can be used to uniquely identify a record.
•    eventId : Link to ddl_events
•    sqlLine : The line number of the executed command
•    sqlText : An sql text line of the command. Taken from the ORA_SQL_TXT function.


The Trigger
CREATE OR REPLACE TRIGGER dtr_ddlEvents
AFTER DDL ON DATABASE
DECLARE

  l_eventId    NUMBER(10,0);
  l_sqlText    ORA_NAME_LIST_T;

BEGIN

  SELECT dsq_ddlEvents.NEXTVAL INTO l_eventId FROM SYS.DUAL;

  INSERT INTO ddl_events
  ( SELECT l_eventId,
           SYSDATE,
           ORA_LOGIN_USER,
           ORA_DICT_OBJ_NAME,
           ORA_DICT_OBJ_OWNER,
           ORA_DICT_OBJ_TYPE,
           ORA_SYSEVENT,
           machine,
           program,
           osuser
      FROM SYS.DUAL,
           SYS.V_$SESSION
     WHERE SYS_CONTEXT('USERENV','SESSIONID' ) = audsid(+) );


  FOR l IN 1..ORA_SQL_TXT(l_sqlText) LOOP
    INSERT INTO ddl_events_sql
    ( eventId, sqlLine, sqlText )
    VALUES
    ( l_eventId, l, l_sqlText(l) );
  END LOOP;

END;
/
 
Auditing the DDL changes is made easy by the DDL triggers. This solution uses and AFTER DDL ON DATABASE clause. This will audit all the changes made on the database. If you are just looking to audit a particular schema the AFTER DDL ON SCHEMA clause could be used instead.

The trigger inserts the data into the into the ddl_events table with data from built-in functions and the v_$session view. The outer join on the v_$session view enables the bulti-in functions to still populate for background processes.

The ddl_events_sql table is then populated by the ORA_SQL_TXT function. The loop populates the ddl_events_sql table for each line of the statement.

Variations
If auditing the database is too much, a single schema can be audited by using AFTER DDL ON SCHEMA in place of AFTER DDL ON DATABASE.

If auditing the sql text gives too much data, this code can easily be removed, or modified so that the first 4000 characters is inserted into the ddl_events table.

The sql text code above includes auditing for password changes. As the password is sensitive you may want to hide it from the log. You can do this by modifying the sql text loop as below.
   FOR l IN 1..ORA_SQL_TXT(l_sqlText) LOOP
    IF  ORA_DICT_OBJ_TYPE = 'USER'
    AND INSTR(UPPER(l_sqlText(l)),'IDENTIFIED BY') != 0
    THEN
      l_sqlText(l) := SUBSTR(l_sqlText(l),1,INSTR(UPPER(l_sqlText(l)),'IDENTIFIED BY')+13)||'*';
    END IF;
    INSERT INTO ddl_events_sql
    ( eventId, sqlLine, sqlText )
    VALUES
    ( l_eventId, l, l_sqlText(l) );
  END LOOP;
The additional if statement checks for user statements that contain IDENTIFIED BY clauses, the text to the right of the clause is then replaced with an asterisk.
I know auditing system can be more expensive so we can skip by adding a small clause to exclude username right after the below line.

 WHERE SYS_CONTEXT('USERENV','SESSIONID' ) = audsid(+) 
     and username not in ('SYS','SYSTEM'));

Further Reading


AskTom: Writing DDL triggers
DBAzine.com: Article on system event auditing 

Tracking DDL changes in 11g



As you all know Oracle provides DDL triggers to track changes to the database.Data from these triggers are used for auditing, change controls etc.

But Oracle 11g also provides specific event for tracking DDL changes.It uses target called SQL_DDL.
These events can be enabled on session or system level.This is shortest command:
SQL> alter session set events ‘trace[SQL_DDL]’;
and to turn off:
SQL>  alter session set events ‘trace[SQL_DDL] off’;
System level:
SQL> alter system set events ‘trace[SQL_DDL]’;
System altered.
SQL>  alter system set events ‘trace[SQL_DDL] off’;
This command can be extended to trace disk , memory or use different resolution etc.List is below:
[disk=DISABLE | LOW | LOWEST | MEDIUM | HIGH | HIGHEST]
[memory=DISABLE | LOW | LOWEST | MEDIUM | HIGH | HIGHEST]
[get_time=DISABLE | DEFAULT | SEQ | HIGHRES | SEQ_HIGHRES ]
[get_stack=DISABLE | DEFAULT | ENABLED ]
For my test I have created simple logon trigger  whic will trace only my userid after logon on database:
CREATE OR REPLACE TRIGGER SYS.trace_ddl
after logon on database
begin
if user like ‘MILADIN’ then
execute immediate ‘alter session set timed_statistics=true’;
execute immediate ‘alter session set max_dump_file_size=unlimited’;
execute immediate ‘alter session set tracefile_identifier=”MILADIN”’;
execute immediate ‘alter session set events ”trace [SQL_DDL]”’;
end if;
end;
/
Here are few examples.
First trace is coming from  create statement.These traces can be used not only to track DDL changes but they are also very
educational especially if you interested into Oracle internals.
Most useful part of course is DDL sql statement but also I can see from trace below that Oracle internal function called ctcdrv is involved with create table statement.This function will be part of call stack for this operation.
Beside sqlid there is object id and transaction properties.
DDL begin in opiprs
session id 127 inc 3293 pgadep 0 sqlid 2k18f2uj8d9xh oct 1 txn 0x907da308 autocommit 1
—– Current SQL Statement for this session (sql_id=2k18f2uj8d9xh) —–
create table test (a number, b number)
ctcdrv
session id 127 inc 3293 pgadep 0 sqlid 2k18f2uj8d9xh DDL on 72076 op-alter_table 0
Creating segment
session id 127 inc 3293 pgadep 0 sqlid 2k18f2uj8d9xh objn 72076 objd 72076 tsn 4 rdba 0x010000c2
DDL end in opiexe
session id 127 inc 3293 pgadep 0 sqlid 2k18f2uj8d9xh txn 0x907da308 autocommit 1 commited 1
Second example is coming from ALTER TABLE command.Oracle is placing exclusive lock in mode 3 and using function ktagetg_ddl.
DDL begin in opiprs
session id 137 inc 49870 pgadep 0 sqlid 22xpbw2mmxhg5 oct 15 txn 0x8f849888 autocommit 1
—– Current SQL Statement for this session (sql_id=22xpbw2mmxhg5) —–
alter table test add ( c varchar2(20))
Lock statement for DDL
session id 137 inc 49870 pgadep 0 sqlid 22xpbw2mmxhg5 string LOCK TABLE “TEST” IN ROW EXCLUSIVE MODE  NOWAIT
ktagetg_ddl sessionid 137 inc 49870 pgadep 0 txn 0x8f849888 table 72076 mode 3
atbdrv
session id 137 inc 49870 pgadep 0 sqlid 22xpbw2mmxhg5 atbdrv DDL on 72076
DDL end in opiexe
session id 137 inc 49870 pgadep 0 sqlid 22xpbw2mmxhg5 txn 0x8f849888 autocommit 1 commited 1
and last is DROP TABLE segment.
Note here that Oracle is renaming table ( placing in recycle bin ) and using lock mode 6 .
DDL begin in opiprs
session id 127 inc 3251 pgadep 0 sqlid 0000000000000 oct 12 txn 0x8f834b98 autocommit 1
—– Current SQL Statement for this session (sql_id=0000000000000) —–
drop table test
ktagetg_ddl sessionid 127 inc 3251 pgadep 0 txn 0x8f834b98 table 72076 mode 6
ktagetg_ddl sessionid 127 inc 3251 pgadep 0 txn 0x8f834b98 table 72076 mode 6
ktagetg_ddl sessionid 127 inc 3251 pgadep 0 txn 0x8f834b98 table 72076 mode 6
ktagetg_ddl sessionid 127 inc 3251 pgadep 0 txn 0x8f834b98 table 72076 mode 6
ktagetg_ddl sessionid 127 inc 3251 pgadep 0 txn 0x8f834b98 table 72076 mode 6
DDL begin in opiprs
session id 127 inc 3251 pgadep 1 sqlid 8qmxb0kjzac3z oct 15 txn 0x8f834b98 autocommit 0
—– Current SQL Statement for this session (sql_id=8qmxb0kjzac3z) —–
ALTER TABLE “MILADIN”.”TEST” RENAME TO “BIN$cZh5wRSSvx7gQAB/AQBWVA==$0”
ktagetg_ddl sessionid 127 inc 3251 pgadep 1 txn 0x8f834b98 table 72076 mode 6
atbdrv
session id 127 inc 3251 pgadep 1 sqlid 8qmxb0kjzac3z atbdrv DDL on 72076
DDL end in opiexe
session id 127 inc 3251 pgadep 1 sqlid 8qmxb0kjzac3z txn 0x8f834b98 autocommit 0 commited 0
DDL end in opiexe
session id 127 inc 3251 pgadep 0 sqlid 0000000000000 txn 0x8f834b98 autocommit 1 commited 1
References:
Metalink: Oracle Database Lock Matrix Doc ID:     749779.1

Auditing in Oracle

The auditing mechanism for Oracle is extremely flexible. Oracle stores information that is relevant to auditing in its data dictionary.

Every time a user attempts anything in the database where audit is enabled the Oracle kernel checks to see if an audit record should be created or updated (in the case or a session record) and generates the record in a table owned by the SYS user called AUD$. This table is, by default, located in the SYSTEM tablespace. This itself can cause problems with potential denial of service attacks. If the SYSTEM tablespace fills up, the database will hang.

init parameters
Until Oracle 10g, auditing is disabled by default, but can be enabled by setting the AUDIT_TRAIL static parameter in the init.ora file.
From Oracle 11g, auditing is enabled for some system level privileges.

SQL> show parameter audit

NAMETYPEVALUE
-----------------------------------------------
audit_file_deststring?/rdbms/audit
audit_sys_operationsbooleanFALSE
audit_syslog_levelstringNONE
audit_trailstringDB
transaction_auditingbooleanTRUE

AUDIT_TRAIL can have the following values.

AUDIT_TRAIL={NONE or FALSE| OS| DB or TRUE| DB_EXTENDED| XML |XML_EXTENDED}

The following list provides a description of each value:
  • NONE or FALSE -> Auditing is disabled. Default until Oracle 10g.
  • DB or TRUE -> Auditing is enabled, with all audit records stored in the database audit trial (AUD$). Default from Oracle 11g.
  • DB_EXTENDED –> Same as DB, but the SQL_BIND and SQL_TEXT columns are also populated.
  • XML-> Auditing is enabled, with all audit records stored as XML format OS files.
  • XML_EXTENDED –> Same as XML, but the SQL_BIND and SQL_TEXT columns are also populated.
  • OS -> Auditing is enabled, with all audit records directed to the operating system's file specified by AUDIT_FILE_DEST.

Note: In Oracle 10g Release 1, DB_EXTENDED was used in place of "DB,EXTENDED". The XML options were brought in Oracle 10g Release 2.


The AUDIT_FILE_DEST parameter specifies the OS directory used for the audit trail when the OS, XML and XML_EXTENDED options are used. It is also the location for all mandatory auditing specified by the AUDIT_SYS_OPERATIONS parameter.

The AUDIT_SYS_OPERATIONS static parameter enables or disables the auditing of operations issued by users connecting with SYSDBA or SYSOPER privileges, including the SYS user. All audit records are written to the OS audit trail.

Run the $ORACLE_HOME/rdbms/admin/cataudit.sql script while connected as SYS (no need to run this, if you ran catalog.sql at the time of database creation).

Start Auditing
Syntax of audit command:
audit {statement_option|privilege_option} [by user] [by {session|access}] [whenever {successful|not successful}]


Only the statement_option or privilege_option part is mandatory. The other clauses are optional and enabling them allows audit be more specific.

There are three levels that can be audited:

Statement level
Auditing will be done at statement level.
Statements that can be audited are found in STMT_AUDIT_OPTION_MAP.
SQL> audit table by scott;

Audit records can be found in DBA_STMT_AUDIT_OPTS.
SQL> select * from DBA_STMT_AUDIT_OPTS;

Object level
Auditing will be done at object level.
These objects can be audited: tables, views, sequences, packages, stored procedures and stored functions.
SQL> audit insert, update, delete on scott.emp by hr;

Audit records can be found in DBA_OBJ_AUDIT_OPTS.
SQL> select * from DBA_OBJ_AUDIT_OPTS;

Privilege level
Auditing will be done at privilege level.
All system privileges that are found in SYSTEM_PRIVILEGE_MAP can be audited.
SQL> audit create tablespace, alter tablespace by all;

Specify ALL PRIVILEGES to audit all system privileges.

Audit records can be found in DBA_PRIV_AUDIT_OPTS.
SQL> select * from DBA_PRIV_AUDIT_OPTS;

Audit options
BY SESSION
Specify BY SESSION if you want Oracle to write a single record for all SQL statements of the same type issued and operations of the same type executed on the same schema objects in the same session.

Oracle database can write to an operating system audit file but cannot read it to detect whether an entry has already been written for a particular operation. Therefore, if you are using an operating system file for the audit trail (that is, the AUDIT_TRAIL initialization parameter is set to OS), then the database may write multiple records to the audit trail file even if you specify BY SESSION.

SQL> audit create, alter, drop on currency by xe by session;
SQL> audit alter materialized view by session;

BY ACCESS 
Specify BY ACCESS if you want Oracle database to write one record for each audited statement and operation.

If you specify statement options or system privileges that audit data definition language (DDL) statements, then the database automatically audits by access regardless of whether you specify the BY SESSION clause or BY ACCESS clause.

For statement options and system privileges that audit SQL statements other than DDL, you can specify either BY SESSION or BY ACCESS. BY SESSION is the default.

SQL> audit update on health by access;
SQL> audit alter sequence by tester by access;

WHENEVER [NOT] SUCCESSFUL 
Specify WHENEVER SUCCESSFUL to audit only SQL statements and operations that succeed.
Specify WHENEVER NOT SUCCESSFUL to audit only SQL statements and operations that fail or result in errors.

If you omit this clause, then Oracle Database performs the audit regardless of success or failure.

SQL> audit insert, update, delete on hr.emp by hr by session whenever not successful;
SQL> audit materialized view by pingme by access whenever successful;

Examples
Auditing for every SQL statement related to roles (create, alter, drop or set a role).
SQL> AUDIT ROLE;

Auditing for every statement that reads files from database directory
SQL> AUDIT READ ON DIRECTORY ext_dir;

Auditing for every statement that performs any operation on the sequence
SQL> AUDIT ALL ON hr.emp_seq;

View Audit Trail
The audit trail is stored in the base table SYS.AUD$.
It's contents can be viewed in the following views:
· DBA_AUDIT_TRAIL
· DBA_OBJ_AUDIT_OPTS
· DBA_PRIV_AUDIT_OPTS
· DBA_STMT_AUDIT_OPTS
· DBA_AUDIT_EXISTS
· DBA_AUDIT_OBJECT
· DBA_AUDIT_SESSION
· DBA_AUDIT_STATEMENT
· AUDIT_ACTIONS
· DBA_AUDIT_POLICIES
· DBA_AUDIT_POLICY_COLUMNS
· DBA_COMMON_AUDIT_TRAIL
· DBA_FGA_AUDIT_TRAIL (FGA_LOG$)
· DBA_REPAUDIT_ATTRIBUTE
· DBA_REPAUDIT_COLUMN

The audit trail contains lots of data, but the following are most likely to be of interest:
Username - Oracle Username.
Terminal - Machine that the user performed the action from.
Timestamp - When the action occurred.
Object Owner - The owner of the object that was interacted with.
Object Name - name of the object that was interacted with.
Action Name - The action that occurred against the object (INSERT, UPDATE, DELETE, SELECT, EXECUTE)

Fine Grained Auditing (FGA), introduced in Oracle9i, allowed recording of row-level changes along with SCN numbers to reconstruct the old data, but they work for select statements only, not for DML such as update, insert, and delete.
From Oracle 10g, FGA supports DML statements in addition to selects.

Several fields have been added to both the standard and fine-grained audit trails:
  • EXTENDED_TIMESTAMP - A more precise value than the existing TIMESTAMP column.
  • PROXY_SESSIONID - Proxy session serial number when an enterprise user is logging in via the proxy method.
  • GLOBAL_UID - Global Universal Identifier for an enterprise user.
  • INSTANCE_NUMBER - The INSTANCE_NUMBER value from the actioning instance.
  • OS_PROCESS - Operating system process id for the oracle process.
  • TRANSACTIONID - Transaction identifier for the audited transaction. This column can be used to join to the XID column on the FLASHBACK_TRANSACTION_QUERY view.
  • SCN - System change number of the query. This column can be used in flashback queries.
  • SQL_BIND - The values of any bind variables if any.
  • SQL_TEXT - The SQL statement that initiated the audit action.
    The SQL_BIND and SQL_TEXT columns are only populated when the AUDIT_TRAIL=DB_EXTENDED or AUDIT_TRAIL=XML_EXTENDED initialization parameter is set.
Maintenance
The audit trail must be deleted/archived on a regular basis to prevent the SYS.AUD$ table growing to an unacceptable size.

Only users who have been granted specific access to SYS.AUD$ can access the table to select, alter or delete from it. This is usually just the user SYS or any user who has permissions. There are two specific roles that allow access to SYS.AUD$ for select and delete, these are DELETE_CATALOG_ROLE and SELECT_CATALOG_ROLE. These roles should not be granted to general users.

Auditing modifications of the data in the audit trail itself can be achieved as follows
SQL> AUDIT INSERT, UPDATE, DELETE ON sys.aud$ BY ACCESS;

To delete all audit records from the audit trail:
SQL> DELETE FROM sys.aud$;

From Oracle 11g R2, we can change audit table's (SYS.AUD$ and SYS.FGA_LOG$) tablespace and we can periodically delete the audit trail records using DBMS_AUDIT_MGMT package.

Disabling Auditing
The NOAUDIT statement turns off the various audit options of Oracle. Use it to reset statement, privilege and object audit options. A NOAUDIT statement that sets statement and privilege audit options can include the BY USER option to specify a list of users to limit the scope of the statement and privilege audit options.

SQL> NOAUDIT;
SQL> NOAUDIT session;
SQL> NOAUDIT session BY scott, hr;
SQL> NOAUDIT DELETE ON emp;
SQL> NOAUDIT SELECT TABLE, INSERT TABLE, DELETE TABLE, EXECUTE PROCEDURE;
SQL> NOAUDIT ALL;
SQL> NOAUDIT ALL PRIVILEGES;
SQL> NOAUDIT ALL ON DEFAULT;

Source: Internet

To Monitor Tablespaces/datafiles

To check all the tablespaces space detail in database:

COLUMN tsname        FORMAT a25
COLUMN allocation_type FORMAT A4 TRU HEADING ALLO
COLUMN contents      FORMAT A4 TRU HEADING MGMT
COLUMN Tot_Size      FORMAT 999,999 HEADING "TOTAL(M)"
COLUMN Tot_Free      FORMAT 999,999 HEADING "FREE(M)"
COLUMN Pct_Free      FORMAT 999 HEADING "FREE %"
COLUMN Fragments     FORMAT 99,999 HEADING "FRAGMTS"
COLUMN Large_Ext     FORMAT 999,999 HEADING "LARG(M)"


SELECT a.tablespace_name TSNAME, SUM(a.tots)/1048576 Tot_Size,
       SUM(a.sumb)/1048576 Tot_Free,
       SUM(a.sumb)*100/sum(a.tots) Pct_Free,
       SUM(a.largest)/1048576 Large_Ext, SUM(a.chunks) Fragments,
       b.contents, b.allocation_type
FROM   (SELECt tablespace_name, 0 tots, SUM(bytes) sumb,
               MAX(bytes) largest, COUNT(*) chunks
        FROM   dba_free_space a
        GROUP BY tablespace_name
        UNION
        SELECT tablespace_name, SUM(bytes) tots, 0, 0, 0
        FROM   dba_data_files
        GROUP BY tablespace_name
        UNION
        SELECT tablespace_name, SUM(bytes) tots, 0, 0, 0
        FROM   dba_temp_files
        GROUP BY tablespace_name) a, dba_tablespaces b
WHERE b.tablespace_name = a.tablespace_name
GROUP BY a.tablespace_name, b.contents, b.allocation_type
Order by 4
/

To check space in tablespace :

set line 180 pages 132
col file_name for a45
col TABLESPACE_NAME for a25
prompt size 2621504k,
Prompt TO increase size by 15% use command as below

prompt select <substitute Tot size of tbs>*.15 from dual;

define ts=&TABLESPACE_NAME
set verify off

SELECT A.TABLESPACE_NAME,round(SUM(A.TOTS)/1024/1024) "Tot size MB",
round(SUM(A.SUMB)/1024/1024) "Tot Free MB",
round(SUM(A.SUMB)*100/SUM(A.TOTS)) "%FREE",
100-round(SUM(A.SUMB)*100/SUM(A.TOTS)) "%USED",
round(SUM(A.LARGEST)/1024/1024) MAX_FREE,SUM(A.CHUNKS) CHUNKS_FREE
FROM (
SELECT TABLESPACE_NAME,0 TOTS,SUM(BYTES) SUMB,
MAX(BYTES) LARGEST,COUNT(*) CHUNKS
FROM SYS.DBA_FREE_SPACE A
GROUP BY TABLESPACE_NAME
UNION
SELECT TABLESPACE_NAME,SUM(BYTES) TOTS,0,0,0
FROM SYS.DBA_DATA_FILES
GROUP BY TABLESPACE_NAME) A, V$INSTANCE B
where A.TABLESPACE_NAME=upper('&ts')
GROUP BY UPPER(B.INSTANCE_NAME),A.TABLESPACE_NAME
/

To check datafile associated with tablespace :

select df.FILE_ID,df.FILE_NAME,df.TABLESPACE_NAME,round(df.BYTES/1024/1024) Allocated,
round(nvl(dfs.BYTES/1024/1024,0)) FREE_SPACE, round(((df.BYTES/1024/1024)-nvl((dfs.BYTES/1024/1024),0))) USED_SPACE
from dba_data_files df,
(select file_id,tablespace_name,sum(bytes) bytes
from dba_free_space
group by file_id,tablespace_name) dfs
where df.FILE_ID=dfs.FILE_ID (+)
AND df.TABLESPACE_NAME=upper('UNDOTBS1')
order by df.FILE_ID
/

To check Tablespace free space:

SELECT TABLESPACE_NAME, SUM(BYTES/1024/1024) "Size (MB)"  FROM DBA_FREE_SPACE GROUP BY TABLESPACE_NAME;
To check Tablespace by datafile:
SELECT tablespace_name, File_id, SUM(bytes/1024/1024)"Size (MB)" FROM DBA_FREE_SPACE
group by tablespace_name, file_id;

To Check Tablespace used and free space %:

SELECT /* + RULE */  df.tablespace_name "Tablespace",
df.bytes / (1024 * 1024) "Size (MB)", SUM(fs.bytes) / (1024 * 1024) "Free (MB)",
Nvl(Round(SUM(fs.bytes) * 100 / df.bytes),1) "% Free",
Round((df.bytes - SUM(fs.bytes)) * 100 / df.bytes) "% Used"
FROM dba_free_space fs,
(SELECT tablespace_name,SUM(bytes) bytes
FROM dba_data_files
GROUP BY tablespace_name) df
WHERE fs.tablespace_name (+)  = df.tablespace_name
GROUP BY df.tablespace_name,df.bytes
UNION ALL
SELECT /* + RULE */ df.tablespace_name tspace,
fs.bytes / (1024 * 1024), SUM(df.bytes_free) / (1024 * 1024),
Nvl(Round((SUM(fs.bytes) - df.bytes_used) * 100 / fs.bytes), 1),
Round((SUM(fs.bytes) - df.bytes_free) * 100 / fs.bytes)
FROM dba_temp_files fs,
(SELECT tablespace_name,bytes_free,bytes_used
 FROM v$temp_space_header
GROUP BY tablespace_name,bytes_free,bytes_used) df
 WHERE fs.tablespace_name (+)  = df.tablespace_name
 GROUP BY df.tablespace_name,fs.bytes,df.bytes_free,df.bytes_used
 ORDER BY 4 DESC;

--or--

Select t.tablespace, t.totalspace as " Totalspace(MB)", round((t.totalspace-fs.freespace),2) as "Used Space(MB)", fs.freespace as "Freespace(MB)", round(((t.totalspace-fs.freespace)/t.totalspace)*100,2) as "% Used", round((fs.freespace/t.totalspace)*100,2) as "% Free" from (select round(sum(d.bytes)/(1024*1024)) as totalspace, d.tablespace_name tablespace from dba_data_files d group by d.tablespace_name) t, (select round(sum(f.bytes)/(1024*1024)) as freespace, f.tablespace_name tablespace from dba_free_space f group by f.tablespace_name) fs where t.tablespace=fs.tablespace order by t.tablespace;
Tablespace (File wise) used and Free space
SELECT SUBSTR (df.NAME, 1, 40) file_name,dfs.tablespace_name, df.bytes / 1024 / 1024 allocated_mb, ((df.bytes / 1024 / 1024) -  NVL (SUM (dfs.bytes) / 1024 / 1024, 0)) used_mb,
NVL (SUM (dfs.bytes) / 1024 / 1024, 0) free_space_mb
FROM v$datafile df, dba_free_space dfs
WHERE df.file# = dfs.file_id(+)
GROUP BY dfs.file_id, df.NAME, df.file#, df.bytes,dfs.tablespace_name
ORDER BY file_name;

To check Growth rate of  Tablespace :

Note: The script will not show the growth rate of the SYS, SYSAUX Tablespace. The script is used in Oracle version 10g onwards.

SELECT TO_CHAR (sp.begin_interval_time,'DD-MM-YYYY') days,
 ts.tsname , max(round((tsu.tablespace_size* dt.block_size )/(1024*1024),2) ) cur_size_MB,
 max(round((tsu.tablespace_usedsize* dt.block_size )/(1024*1024),2)) usedsize_MB
 FROM DBA_HIST_TBSPC_SPACE_USAGE tsu, DBA_HIST_TABLESPACE_STAT ts, DBA_HIST_SNAPSHOT sp,
 DBA_TABLESPACES dt
 WHERE tsu.tablespace_id= ts.ts# AND tsu.snap_id = sp.snap_id
 AND ts.tsname = dt.tablespace_name AND ts.tsname NOT IN ('SYSAUX','SYSTEM')
 GROUP BY TO_CHAR (sp.begin_interval_time,'DD-MM-YYYY'), ts.tsname
 ORDER BY ts.tsname, days;
List all Tablespaces with free space < 10% or full space> 90%
Select a.tablespace_name,sum(a.tots/1048576) Tot_Size,
sum(a.sumb/1024) Tot_Free, sum(a.sumb)*100/sum(a.tots) Pct_Free,
ceil((((sum(a.tots) * 15) - (sum(a.sumb)*100))/85 )/1048576) Min_Add
from (select tablespace_name,0 tots,sum(bytes) sumb
from dba_free_space a
group by tablespace_name
union
Select tablespace_name,sum(bytes) tots,0 from
dba_data_files
group by tablespace_name) a
group by a.tablespace_name
having sum(a.sumb)*100/sum(a.tots) < 10
order by pct_free;

Script to find all object Occupied space for a Tablespace :

Select OWNER, SEGMENT_NAME, SUM(BYTES)/1024/1024 "SZIE IN MB" from dba_segments
where TABLESPACE_NAME = 'SDH_HRMS_DBF'
group by OWNER, SEGMENT_NAME;
Which schema are taking how much space
Select obj.owner "Owner", obj_cnt "Objects", decode(seg_size, NULL, 0, seg_size) "size MB"
from (select owner, count(*) obj_cnt from dba_objects group by owner) obj,
 (select owner, ceil(sum(bytes)/1024/1024) seg_size  from dba_segments group by owner) seg
  where obj.owner  = seg.owner(+)
  order    by 3 desc ,2 desc, 1;

To Check Default Temporary Tablespace Name:

Select * from database_properties where PROPERTY_NAME like '%DEFAULT%';
To know default and Temporary Tablespace for particualr User:
Select username,temporary_tablespace,default_tablespace from dba_users where username='HRMS';
To know Default Tablespace for All User:
Select default_tablespace,temporary_tablespace,username from dba_users;
To Check Datafiles used and Free Space:
SELECT SUBSTR (df.NAME, 1, 40) file_name,dfs.tablespace_name, df.bytes / 1024 / 1024 allocated_mb,
((df.bytes / 1024 / 1024) -  NVL (SUM (dfs.bytes) / 1024 / 1024, 0)) used_mb,
NVL (SUM (dfs.bytes) / 1024 / 1024, 0) free_space_mb
FROM v$datafile df, dba_free_space dfs
WHERE df.file# = dfs.file_id(+)
GROUP BY dfs.file_id, df.NAME, df.file#, df.bytes,dfs.tablespace_name
ORDER BY file_name;

To check Used free space in Temporary Tablespace:

SELECT tablespace_name, SUM(bytes_used/1024/1024) USED, SUM(bytes_free/1024/1024) FREE
FROM   V$temp_space_header GROUP  BY tablespace_name;

SELECT   A.tablespace_name tablespace, D.mb_total,
         SUM (A.used_blocks * D.block_size) / 1024 / 1024 mb_used,
         D.mb_total - SUM (A.used_blocks * D.block_size) / 1024 / 1024 mb_free
FROM     v$sort_segment A,
         ( SELECT   B.name, C.block_size, SUM (C.bytes) / 1024 / 1024 mb_total
         FROM     v$tablespace B, v$tempfile C
         WHERE    B.ts#= C.ts#
         GROUP BY B.name, C.block_size
         ) D
WHERE    A.tablespace_name = D.name
GROUP by A.tablespace_name, D.mb_total;

Sort (Temp) space used by Session :

SELECT   S.sid || ',' || S.serial# sid_serial, S.username, S.osuser, P.spid, S.module, S.program, SUM (T.blocks) * TBS.block_size / 1024 / 1024 mb_used,
T.tablespace, COUNT(*) sort_ops
FROM v$sort_usage T, v$session S, dba_tablespaces TBS, v$process P
WHERE T.session_addr = S.saddr
AND S.paddr = P.addr AND T.tablespace = TBS.tablespace_name
GROUP BY S.sid, S.serial#, S.username, S.osuser, P.spid, S.module, S.program, TBS.block_size, T.tablespace ORDER BY sid_serial;
Sort (Temp) Space Usage by Statement
SELECT S.sid || ',' || S.serial# sid_serial, S.username, T.blocks * TBS.block_size / 1024 / 1024 mb_used, T.tablespace,T.sqladdr address, Q.hash_value, Q.sql_text
FROM v$sort_usage T, v$session S, v$sqlarea Q, dba_tablespaces TBS
WHERE T.session_addr = S.saddr
AND T.sqladdr = Q.address (+) AND T.tablespace = TBS.tablespace_name
ORDER BY S.sid;

Who is using which UNDO or TEMP segment?

SELECT TO_CHAR(s.sid)||','||TO_CHAR(s.serial#) sid_serial,
NVL(s.username, 'None') orauser,s.program, r.name undoseg,
t.used_ublk * TO_NUMBER(x.value)/1024||'K' "Undo"
FROM sys.v_$rollname r, sys.v_$session s, sys.v_$transaction t, sys.v_$parameter   x
WHERE s.taddr = t.addr AND r.usn   = t.xidusn(+) AND x.name  = 'db_block_size';
Who is using the Temp Segment?
SELECT b.tablespace, ROUND(((b.blocks*p.value)/1024/1024),2)||'M' "SIZE",
a.sid||','||a.serial# SID_SERIAL, a.username, a.program
FROM sys.v_$session a,
sys.v_$sort_usage b, sys.v_$parameter p
WHERE p.name  = 'db_block_size' AND a.saddr = b.session_addr
ORDER BY b.tablespace, b.blocks;
Total Size and Free Size of Database:
Select round(sum(used.bytes) / 1024 / 1024/1024 ) || ' GB' "Database Size",
round(free.p / 1024 / 1024/1024) || ' GB' "Free space"
from (select bytes from v$datafile
      union all
      select bytes from v$tempfile
      union all
      select bytes from v$log) used, 
(select sum(bytes) as p from dba_free_space) free
group by free.p;

To find used space of datafiles:

SELECT SUM(bytes)/1024/1024/1024 "GB" FROM dba_segments;
IO status of all of the datafiles in database:
WITH total_io AS
     (SELECT SUM (phyrds + phywrts) sum_io
        FROM v$filestat)
SELECT   NAME, phyrds, phywrts, ((phyrds + phywrts) / c.sum_io) * 100 PERCENT,
         phyblkrd, (phyblkrd / GREATEST (phyrds, 1)) ratio
    FROM SYS.v_$filestat a, SYS.v_$dbfile b, total_io c
   WHERE a.file# = b.file#
ORDER BY a.file#;
Displays Smallest size the datafiles can shrink to without a re-organize.
SELECT a.tablespace_name, a.file_name, a.bytes AS current_bytes, a.bytes - b.resize_to AS shrink_by_bytes, b.resize_to AS resize_to_bytes
FROM   dba_data_files a, (SELECT file_id, MAX((block_id+blocks-1)*&v_block_size) AS resize_to
        FROM   dba_extents
        GROUP by file_id) b
        WHERE  a.file_id = b.file_id
        ORDER BY a.tablespace_name, a.file_name;
Scripts to Find datafiles increment details:
Select  SUBSTR(fn.name,1,DECODE(INSTR(fn.name,'/',2),0,INSTR(fn.name,':',1),INSTR(fn.name,'/',2))) mount_point,tn.name   tabsp_name,fn.name   file_name,
ddf.bytes/1024/1024 cur_size, decode(fex.maxextend,
NULL,ddf.bytes/1024/1024,fex.maxextend*tn.blocksize/1024/1024) max_size,
nvl(fex.maxextend,0)*tn.blocksize/1024/1024 - decode(fex.maxextend,NULL,0,ddf.bytes/1024/1024)   unallocated,nvl(fex.inc,0)*tn.blocksize/1024/1024  inc_by
from  sys.v_$dbfile fn,    sys.ts$  tn,    sys.filext$ fex,    sys.file$  ft,    dba_data_files ddf
where    fn.file# = ft.file# and  fn.file# = ddf.file_id
and    tn.ts# = ft.ts# and    fn.file# = fex.file#(+)
order by 1;


Maximum datafile shrink possible in tablespace:

set verify off
set pagesize 999
set linesize 160
 column file_name format a60 word_wrapped
column smallest format 999,990 heading "Smallest|Size|Poss."
column currsize format 999,990 heading "Current|Size"
column savings  format 999,990 heading "Poss.|Savings"
break on report
compute sum of savings on report
 column value new_val blksize
select value from v$parameter where name = 'db_block_size' ;

select file_name,
       ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) smallest,
       ceil( blocks*&&blksize/1024/1024) currsize,
       ceil( blocks*&&blksize/1024/1024) -
       ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) savings
from dba_data_files a,
     ( select file_id, max(block_id+blocks-1) hwm
         from dba_extents
         where tablespace_name = 'XXXXXXXXX'
        group by file_id ) b
where a.file_id = b.file_id(+)
  and tablespace_name = 'XXXXXXXXXXXXXXXXX'
order by a.tablespace_name, a.file_name ;

To see get the command for possible datafile shirnk [in tablespace_name] :

column cmd format a155 word_wrapped

select 'alter database datafile '''||file_name||''' resize ' ||
       ceil( (nvl(hwm,1)*&&blksize)/1024/1024 )  || 'm;' cmd
from dba_data_files a,
     ( select file_id, max(block_id+blocks-1) hwm
       from dba_extents
       where tablespace_name = 'XXXXXXXX'
       group by file_id ) b
where a.file_id = b.file_id(+)
  and tablespace_name = 'XXXXXXXXX'
  and ceil( blocks*&&blksize/1024/1024) -
      ceil( (nvl(hwm,1)*&&blksize)/1024/1024 ) > 0
order by a.tablespace_name, a.file_name ;

How to grant permission to directory ?

Directory privileges: READ and WRITE :

Eg: granting read on bfile_dir to userName

GRANT READ ON DIRECTORY bfile_dir TO userName;

You can see all the privileges for all directories with the following script
 
select
    *
from 
   all_tab_privs
where 
   table_name in
  (select 
      directory_name 
   from 
      dba_directories);
 

This script display directory privileges for a list of granted privileges:


set lines 110
 
col privilege format a12
col grantee   format  a25
col owner format  a25
 
select 
   p.grantee, p.privilege, p.owner, d.directory_name 
from 
   dba_tab_privs p,

    dba_directories d where    p.table_name=d.directory_name and    (grantee in ('xxx', 'yyy') or    grantee in (select granted_role from dba_role_privs


How to remove unused components in database ?

First check the installed components in database :

set line 200;
set pagesize 9999;
col COMP_ID format a15;
col COMP_NAME format a50;
select COMP_ID,COMP_NAME,STATUS from dba_registry;

How to change Database Directory Path?

CREATE OR REPLACE directory <directory name> AS '<O/S directory>';


SQL> SELECT * FROM dba_directories WHERE directory_name = 'DUMP_DIR';

OWNER                          DIRECTORY_NAME
------------------------------ ------------------------------
DIRECTORY_PATH
--------------------------------------------------------------------------------
SYS                            DUMP_DIR
/u04/oradata1

SQL> CREATE OR REPLACE directory DUMP_DIR AS '/u01/oradata';


Directory created.

SQL> SELECT * FROM dba_directories WHERE directory_name = 'DUMP_DIR';
OWNER                          DIRECTORY_NAME
------------------------------ ------------------------------
DIRECTORY_PATH
--------------------------------------------------------------------------------
SYS                            DUMP_DIR
/u01/oradata

SQL>



## This has changed the directory path from /u04 to /u01.



Oracle Autonomous Database: The Role of the DBA and can AWS beat Oracle Cloud ?


Here we go, watch a nice Video by Maria Colgan 

       

 so what's Next ? ?   Can AWS beat Oracle Cloud ? cannot - watch 
                              
            

Do we need to recreate views in a table after performing an Oracle table reorg ?

We are performing the following steps for reorg:

1> alter table x move;
2> alter index y rebuild;


Do we need to recreate all the concerned VIEWS for these tables?

You do not need to recreate the views. If the view is INVALID due to the move, it will be automatically recompiled and validated the next time the view is accessed.

How does Oracle reuse the Expired and Unexpired undo extents?

A frequent question that I have received from many DBAs is: my undo tablespace is almost full, how can I be sure that the space will be reused?
Well, First you have to know that there are two kind of undo management: Auto and Manual.
Oracle recommends to use Auto Undo Managements so that's where I will focus.
When you are using Auto Undo Management Oracle Manages all the Undo Segments and its extents. Oracle uses some algorithms in order to allocate space when a transaction is asking for it. Coming back to the question, will the space be reused? I could say that Yes. Most of the times the undo space (Expired and if it is needed Unexpired extents) is reused, the only exception is when Retention Guarantee is enabled, but this is not enabled by default. Also you have to be sure that Oracle will never reuse Active Extents from a transaction.
You can see if the undo tablespace has retention Guarantee enabled with the following query:
select retention from dba_tablespaces where tablespace_name='<tbs_name>';
RETENTION
-----------
NOGUARANTEE
So that's the only Exception when the UNEXPIRED Extents will not be reused, instead of this, if there no any other way to get free space, the operation will fail. When you have retention guarantee disabled, the following algorithms are in place.
When we execute an operations that needs to allocate undo space:
  1. Allocate an extent in an undo segment which has no active transaction. Why in other segment? Because Oracle tries to distribute transactions over all undo segments.
  2. If no undo segment was found then oracle tries to online an off-line undo segment and use it to assign the new extent..
  3. If no undo segments was possible to online, then Oracle creates a new undo segment and use it.
  4. If the free space doesn't permit creation of undo segment, then Oracle tries to reuse an expired extent from the current undo segments.
  5. If failed, Oracle tries to reuse an expired extent from another undo segment.
  6. If failed, Oracle tries to autoextend a datafile (if autoextensible=yes)
  7. If failed, Oracle tries to reuse an unexpired extent from the current undo segment.
  8. If failed, Oracle tries to reuse an unexpired extent from another undo segment.
  9. If failed, then the operation will fail.
For a running transaction associated with undo segment/ extent and it needs more undo space:
  1. If the current extent has more free blocks then use the next free block that is all ready allocated to the extent.
  2. If the current extent does not have free blocks and if the next extent of the segment has expired then wrap in the the next extent and return the first block.
  3. If the next extent has not expired then get space from the UNDO tablespace. If a free extent is available then allocate it to the undo segment.
  4. If there is no free extent available then reuse from an offline undo segment. Deallocate the extent from the offline undo segment and add it to the current undo segment.
  5. Steal from online undo segment. Deallocate the extent from the online undo segment and add it to the current undo segment.
Note: The only different with retention guarantee is enabled is that Unexpired Extents will not be reused. 
In the following example, I will show you easily and quickly the behaviour of the first algorithm when we have an undo tablespace with autoextend=on and also with autoextend=off.
Example 1: Autoextend off
For this example I am using an undo tablespace of 5MB. The following datafile is the only one in the tablespace:
SQL> select tablespace_name, file_name,autoextensible, bytes/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1';
TABLESPACE_NAME FILE_NAME                                  AUT MB
--------------- ------------------------------------------ --- ----------
UNDOTBS1        +DATA/orcl/datafile/undotbs1.264.882411811 NO  5
I was monitoring the Undo extents while I was performing some updates in other session, the idea is to see how the expired and unexpired extents will be reused.
1* select status, count(*) Num_Extents, sum(blocks) Num_Blocks, round((sum(bytes)/1024/1024),2) MB from dba_undo_extents group by status order by status
STATUS    NUM_EXTENTS 
--------- ----------- 
EXPIRED    7 
UNEXPIRED  41
No Active extents are created.
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    9 <--There were free extents to use 
EXPIRED   6 <--1 extent was reused
UNEXPIRED 40 <--1 extent already expired
STATUS     NUM_EXTENTS 
--------- ----------- 
ACTIVE    11 <--There were free extents to use 
EXPIRED   6 
UNEXPIRED 40
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    13 <--There were free extents to use
EXPIRED   6 
UNEXPIRED 40
STATUS    NUM_EXTENTS
--------- ----------- 
ACTIVE    15 <--There were free extents to use
EXPIRED   6 
UNEXPIRED 40
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    17 <--There were free extents to use
EXPIRED   6 
UNEXPIRED 40
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    19 
EXPIRED   6 
UNEXPIRED 31 <--unexpired extents were reused
Why Expired extents were not reused? Well, I am performing updates in batches of 10,000 so perhaps the extents that already exists are too small to allocate the undo data that my update generated. Remember that the Undo tablespace extents are autoallocated, so the first extents are small, (64KB at the beginning).
STATUS     NUM_EXTENTS 
--------- ----------- 
ACTIVE     29 
EXPIRED    6 
UNEXPIRED  29 <--unexpired extents were reused
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    31 
EXPIRED   6 
UNEXPIRED 27 <--unexpired extents were reused
STATUS     NUM_EXTENTS
--------- ----------- 
ACTIVE    33 
EXPIRED   6 
UNEXPIRED 25 <--unexpired extents were reused
STATUS     NUM_EXTENTS 
--------- ----------- 
ACTIVE    35 
EXPIRED   6 
UNEXPIRED 23 <--unexpired extents were reused
STATUS    NUM_EXTENTS
--------- ----------- 
ACTIVE    37 
EXPIRED   6 
UNEXPIRED 21 <--unexpired extents were reused
STATUS    NUM_EXTENTS 
--------- -----------
ACTIVE    39 
EXPIRED   6 
UNEXPIRED 19
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    41 
EXPIRED   6 
UNEXPIRED 17 <--unexpired extents were reused
STATUS    NUM_EXTENTS 
--------- -----------
ACTIVE    43 
EXPIRED   6 
UNEXPIRED 15 <--unexpired extents were reused
STATUS    NUM_EXTENTS
--------- ----------- 
ACTIVE    45 
EXPIRED   6 
UNEXPIRED 13 <--unexpired extents were reused
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    46 
EXPIRED   6 
UNEXPIRED 12 <--unexpired extents were reused
At this time I got the following error:
ERROR at line 1:
ORA-30036: unable to extend segment by 8 in undo tablespace 'UNDOTBS1'
This is because both Expired and Unexpired extents were not big enough to allocate my undo data and since the Tablespace has autoextend disabled Oracle raised an error saying that no more free space was found. As you can see Oracle did not resize any datafile:
SQL> select tablespace_name, file_name,autoextensible, bytes/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1';
TABLESPACE_NAME FILE_NAME                                   AUT MB
--------------- -----------------------------------------  ---  ----------
UNDOTBS1        +DATA/orcl/datafile/undotbs1.264.882411811 YES  5
Example 2: Autoextend=on
SQL> alter database datafile '+DATA/orcl/datafile/undotbs1.264.882411811' autoextend on next 1M maxsize 1G;
Database altered.
SQL> select tablespace_name, file_name,autoextensible, bytes/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1';
TABLESPACE_NAME FILE_NAME                                  AUT  MB
--------------- ------------------------------------------ ---- ------
UNDOTBS1        +DATA/orcl/datafile/undotbs1.264.882411811 YES  7
1* select status, count(*) Num_Extents, sum(blocks) Num_Blocks, round((sum(bytes)/1024/1024),2) MB from dba_undo_extents group by status order by status
STATUS    NUM_EXTENTS 
--------- ----------- 
EXPIRED   54 
UNEXPIRED 29
No Active Extents are created.
SQL> r
1* select status, count(*) Num_Extents, sum(blocks) Num_Blocks, round((sum(bytes)/1024/1024),2) MB from dba_undo_extents group by status order by status
STATUS     NUM_EXTENTS
--------- ----------- 
ACTIVE     3 
EXPIRED    52 <--Expired extents were reused 
UNEXPIRED  28
STATUS     NUM_EXTENTS 
--------- ----------- 
ACTIVE     7 
EXPIRED    48 <--Expired extents were reused 
UNEXPIRED  28
STATUS     NUM_EXTENTS
--------- ----------- 
ACTIVE    11 
EXPIRED   38 <--Expired extents were reused 
UNEXPIRED 28
STATUS     NUM_EXTENTS 
--------- ----------- 
ACTIVE    19 
EXPIRED   34 <--Expired extents were reused 
UNEXPIRED 28
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    23 
EXPIRED   30 <--Expired extents were reused 
UNEXPIRED 28
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    27 
EXPIRED   20 <--Expired extents were reused 
UNEXPIRED 28
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    36 
EXPIRED   10 <--Expired extents were reused 
UNEXPIRED 28
STATUS    NUM_EXTENTS 
--------- -----------
ACTIVE    40 
EXPIRED   11 <--Expired extents were reused 
UNEXPIRED 28
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    45 
EXPIRED   9 <--Expired extents were reused 
UNEXPIRED 28
Checking the datafile size:
SQL> r
1* select tablespace_name, file_name,autoextensible, bytes/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1'
TABLESPACE_NAME FILE_NAME                                  AUT MB
--------------- ------------------------------------------ --- ----------
UNDOTBS1        +DATA/orcl/datafile/undotbs1.264.882411811 YES 6
ok, So far the datafile was resized 1 time only, adding 1 MB more.
SQL> r
1* select status, count(*) Num_Extents, sum(blocks) Num_Blocks, round((sum(bytes)/1024/1024),2) MB from dba_undo_extents group by status order by status
STATUS    NUM_EXTENTS
--------- ----------- 
ACTIVE    48 <--Datafile was autoextended and more free extents are available 
EXPIRED   8 
UNEXPIRED 28
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    48 <--Datafile was autoextended and more free extents are available 
EXPIRED   8 
UNEXPIRED 28
STATUS    NUM_EXTENTS
--------- ----------- 
ACTIVE    48 <--Datafile was autoextended and more free extents are available 
EXPIRED   8 
UNEXPIRED 28
STATUS    NUM_EXTENTS 
--------- ----------- 
ACTIVE    48 <--Datafile was autoextended and more free extents are available 
EXPIRED   8 
UNEXPIRED 28
The tablespace will keep increasing its size until all the datafiles are full.
Look at the new datafile size:
SQL> select tablespace_name, file_name,autoextensible, bytes/1024/1024 MB from dba_data_files where tablespace_name='UNDOTBS1';
TABLESPACE_NAME FILE_NAME                                  AUT MB
--------------- ------------------------------------------ --- ----------
UNDOTBS1        +DATA/orcl/datafile/undotbs1.264.882411811 YES 11

In order to know how many times the undo tablespace was asking for more free space, how many blocks were reused and so on, you can query the view v$undostat. This view shows statistics every 10 minutes:
SQL> select begin_time, 
UNXPSTEALCNT "#UnexpiredBlksTaken", 
EXPSTEALCNT "#ExpiredBlksTaken",
NOSPACEERRCNT "SpaceRequests"
from v$undostat order by begin_time; 2 3 4 5
BEGIN_TIME       #UnexpiredBlksTaken #ExpiredBlksTaken SpaceRequests
---------------- ------------------- ----------------- -------------
15-06-2015 02:24 6                   2                 6
15-06-2015 02:34 1                   0                 1
15-06-2015 02:44 11                  12                2
15-06-2015 02:54 76                  42                38
15-06-2015 03:04 71                  71                1
15-06-2015 03:14 0                   4                 0
15-06-2015 03:24 0                   10                0
15-06-2015 03:34 0                   0                 0
15-06-2015 03:44 0                   0                 0
9 rows selected.
Why we are seeing here a lot of Unexpired and Expired blocks reused before "15-06-2015 03:14"? This was because I was executing Updates which generates Undo data and the undo tablespace had autoextend disabled, so it started to reuse first the Expired Blocks and then it Unexpired blocks.
Why between "15-06-2015 03:14" and "15-06-2015 03:24" there were no Unexpired blocks reused but only Expired blocks? This was because at that time the undo tablespace had autoextend enabled, BUT (remember this) Oracle will not autoextend the tablespace immediately when it needs more free space, first Oracle look at the Expired Blocks and only when there is no any other Expired blocks as free then the tablespace is autoextended (The expired extents are reused at the end, until all the datafiles are full and they can not being autoextended more).
Why after "15-06-2015 03:34" there was no Expired and Unexpired blocks reused? This was becuase The All the Expired blocks that could be reused was already reused and the tablespace was able to be autoextended so the tablespace just kept getting larger.
References:
Troubleshooting ORA-30036 - Unable To Extend Undo Tablespace (Doc ID 460481.1)
Explaining ORA-1555 Error (Doc ID 467872.1)