Updates

    Oracle DBA Silver Bullets – Performance Queries

    0 comments
    Just thought to share few queries from my repository. It may be useful for all new DBAs. Of course these are quite old ones and you can do most of them through Enterprise Manager, still we DBAs always like command line :-)

    Show sessions that are blocking each other :

    select 'SID ' || l1.sid ||' is blocking  ' || l2.sid blocking
    from v$lock l1, v$lock l2
    where l1.block =1 and l2.request > 0
    and l1.id1=l2.id1
    and l1.id2=l2.id2
    /

    Show locked objects :

    set lines 100 pages 999
    col username  format a20
    col sess_id  format a10
    col object format a25
    col mode_held format a10
    select oracle_username || ' (' || s.osuser || ')' username
    , s.sid || ',' || s.serial# sess_id
    , owner || '.' || object_name object
    , object_type
    , decode( l.block
     , 0, 'Not Blocking'
     , 1, 'Blocking'
     , 2, 'Global') status
    , decode(v.locked_mode
     , 0, 'None'
     , 1, 'Null'
     , 2, 'Row-S (SS)'
     , 3, 'Row-X (SX)'
     , 4, 'Share'
     , 5, 'S/Row-X (SSX)'
     , 6, 'Exclusive', TO_CHAR(lmode)) mode_held
    from v$locked_object v
    , dba_objects d
    , v$lock l
    , v$session s
    where  v.object_id = d.object_id
    and  v.object_id = l.id1
    and  v.session_id = s.sid
    order by oracle_username
    , session_id
    /

    Show which row is locked :

    select do.object_name
    , row_wait_obj#
    , row_wait_file#
    , row_wait_block#
    , row_wait_row#
    , dbms_rowid.rowid_create (1, ROW_WAIT_OBJ#, ROW_WAIT_FILE#,
        ROW_WAIT_BLOCK#, ROW_WAIT_ROW#)
    from v$session s
    , dba_objects do
    where sid=&sid
    and  s.ROW_WAIT_OBJ# = do.OBJECT_ID
    /
    
    Then select the row with that rowid...
    
    select * from <table> where rowid=<rowid>;

    List locks :

    column lock_type format a12
    column mode_held format a10
    column mode_requested format a10
    column blocking_others format a20
    column username format a10
    SELECT session_id
    , lock_type
    , mode_held
    , mode_requested
    , blocking_others
    , lock_id1
    FROM dba_lock l
    WHERE  lock_type NOT IN ('Media Recovery', 'Redo Thread')
    /

    Show all ddl locks in the system :

    select ses.username
    , ddl.session_id
    , ses.serial#
    , owner || '.' || ddl.name object
    , ddl.type
    , ddl.mode_held
    from dba_ddl_locks ddl
    , v$session ses
    where owner like '%userid%'
    and ddl.session_id = ses.sid
    /

    Generate kill statement for ddl locking sessions :

    select    'alter system kill session ''' || ddl.session_id || ',' || ses.serial# || ''' immediate;'
    from    dba_ddl_locks ddl
    ,    v$session ses
    where    owner like '%userid%'
    and    ddl.session_id = ses.sid
    /

    Show currently exectuing sql :

    select sql_text
    from v$sqlarea
    where users_executing > 0
    /

    Session statistics :

    select    sn.name
    ,    st.value
    from    v$sesstat st
    ,    v$statname sn
    where    st.STATISTIC# = sn.STATISTIC#
    and    st.VALUE > 0
    and    st.SID = &SID
    order     by value desc
    /

    Resource intensive sql :

    change 8192 to match block size
    
    select sql_text
    ,      executions
    ,      to_char((((disk_reads+buffer_gets)/executions) * 8192)/1048576, '9,999,999,990.00')
     as total_gets_per_exec_mb
    ,      to_char((( disk_reads             /executions) * 8192)/1048576, '9,999,999,990.00')
     as disk_reads_per_exec_mb
    ,      to_char((( buffer_gets            /executions) * 8192)/1048576, '9,999,999,990.00')
     as buffer_gets_per_exec_mb
    ,      parsing_user_id
    from   v$sqlarea
    where  executions > 10
    order by 6 desc
    /

    File io stats :

    Requires timed_statistics=true
    
    set lines 80 pages 999
    col fname heading "File Name" format a60
    col sizemb heading "Size(Mb)" format 99,999
    col phyrds heading "Reads" format 999,999,999
    col readtim heading "Time" format 99.999
    col phywrts heading "Writes" format 9,999,999
    col writetim heading "Time" format 99.999
    select     lower(name) fname
    ,          (bytes / 1048576) sizemb
    ,          phyrds
    ,    readtim
    ,          phywrts
    ,    writetim
    from       v$datafile df
    ,          v$filestat fs
    where      df.file# = fs.file#
    order      by 1
    /

    In session tracing :

    To switch it on:
    
    exec dbms_system.set_sql_trace_in_session (<sid>, <serial#>, true);
    
    To switch it off:
    
    exec dbms_system.set_sql_trace_in_session (<sid>, <serial#>, false);

    switch on event 10046 :

    To switch it on:
    
    alter session set events '10046 trace name context forever, level 8'; 
    
    To switch it off:
    
    alter session set events '10046 trace name context off';
    Note. use tkprof to interpret the results.

    Rows per block :

    select    avg(row_count) avg
    , max(row_count) max
    , min(row_count) min
    from      (
     select  count(*) row_count
     from    &table_name
     group   by substr(rowid, 1, 15)
     )
    /

    Show the buffer cache advisory :

    Note. The current setting is halfway down and has a read factor of one.
    
    set lines 100 pages 999
    col est_mb format 99,999
    col estd_physical_reads format 999,999,999,999,999
    select    size_for_estimate est_mb
    ,    estd_physical_read_factor
    ,    estd_physical_reads
    from    v$db_cache_advice
    where    name = 'DEFAULT'
    order by size_for_estimate
    /
    
    db_cache_advice needs to be on for the above to work
    
    alter system set db_cache_advice=on;

    Script to find out Backups taken and their duration in last 24 hours

    0 comments
    To get a picture of all the full or incremental backups taken along with the time it took, use the below script


    select decode(BACKUP_TYPE, 'L', 'ARCH', 'D', 'DB', 'I', 'INC',
                  'Unknown type='||BACKUP_TYPE) TYPE,
           to_char(a.start_time, 'DDMON HH24:MI') start_time,
           to_char(a.elapsed_seconds/60, '99.9')||' Min' DURATION,
           substr(handle, -35) handle,
           nvl(d.file#, l.sequence#) file#, nvl(d.blocks, l.blocks) blocks
    from   SYS.V_$BACKUP_SET a, SYS.V_$BACKUP_PIECE b,
           SYS.V_$BACKUP_DATAFILE d, SYS.V_$BACKUP_REDOLOG l
    where  a.start_time between sysdate-1 and sysdate
      and  a.SET_STAMP = b.SET_STAMP
      and  a.SET_STAMP = d.SET_STAMP(+)
      and  a.SET_STAMP = l.SET_STAMP(+)
    order  by start_time, file#



    This shows the backup of all datafiles and archive log files

    Script to Compile all invalid Materialized Views in a schema

    0 comments
    select 'alter '||object_type||' '||owner||'."'||object_name||'" compile;' from dba_objects where owner = 'OWNER' and object_type = 'MATERIALIZED VIEW' and status <> 'VALID'

    execute the above statement, copy the output and run it in SQLPLUS

    OR

    SET SERVEROUTPUT ON 
    BEGIN
      FOR i IN (SELECT owner,object_name, object_type FROM   dba_objects
                      WHERE  object_type IN ('MATERIALIZED VIEW')
                      AND    status <> 'VALID'
                      AND OWNER='SCHEMA NAME'
                      ORDER BY 2)
      LOOP
        BEGIN
          IF i.object_type = 'MATERIALIZED VIEW' THEN
            EXECUTE IMMEDIATE 'ALTER ' || i.object_type ||' "' || i.owner || '"."' || i.object_name || '" COMPILE';
        
          END IF;
        EXCEPTION
          WHEN OTHERS THEN
            DBMS_OUTPUT.put_line(i.object_type || ' : ' || i.owner ||' : ' || i.object_name);
        END;
      END LOOP;
    END;


    you can use the following in SQLPLUS if need to compile all objects in schema

    exec dbms_utility.compile_schema('SCHEMA NAME')

    Script to find out if any new table/procedure added in the schema in past 24 hours

    0 comments
    set serveroutput on
    declare
    v varchar2(2000);
    begin
         for i in (select object_name,object_type from dba_objects where to_date(created,'yy-mm-dd') >= to_date(sysdate-1,'yy-mm-dd') and owner = 'USER')
    loop

    select dbms_metadata.get_ddl(i.object_type,i.object_name,'USER') into v from dual;
    dbms_output.put_line(v);
    end loop;
    end;

    Find duplicate columns from all tables in a schema

    0 comments
    The below script is used to find the same columns appearing in multiple tables of a particular schema


    SELECT column_name,data_type,data_length,nullable,table_name
    FROM dba_tab_columns
    WHERE column_name IN
    (
        SELECT column_name
        FROM dba_tab_columns
        GROUP BY
            column_name
        HAVING COUNT(1) > 1  -- more than one value
    )
    and owner = 'USER' -- provide the user name
    AND COLUMN_NAME LIKE '%TIME%'
    ORDER BY column_name

    Difference b/w Oracle Restore and Recovery

    0 comments
    Restore and recovery are two separate steps. Restore is the process of copying back data-files from the backup files.
    Recovery is the process of applying transaction information to the data-files to recover them to the state they were in just before the failure occurred.

    See the sample example below in case the database has to recovered with the loss of any datafile assuming the controls file, archived redo log file and online redo log files are available.


     RMAN> connect target / 
     RMAN> startup mount; 
     RMAN> restore database; 

     You’ll see several lines of output as RMAN tells you what it is restoring.    

     Next recover your database as follows:

     RMAN> recover database; 

     You can now open your database for use with the alter database opencommand:

      RMAN> alter database open; 
      database opened

       How It Works

        RMAN uses information stored in the control file to determine where to retrieve backups and which files to      restore and recover.



    When you issue the recover database command, RMAN will automatically apply redo to any datafiles that need recovery. The recovery process includes applying changes found in the following:

    •Incremental backup pieces (applicable only if using incremental backups)
    •Archived redo log files (generated since the last backup or last incremental backup that is applied)
    •Online redo log files (current and unarchived)


    You can open your database after the restore and recovery process is complete. If you restore from a backup control file, you are required to open your database with the open resetlogs command.

    Enabling/Disabling Archivelog mode in Oracle

    0 comments
    Enabling Archivelog Mode
    SQL> connect sys/password as sysdba
    SQL> shutdown immediate;
    SQL> startup mount;
    SQL> alter database archivelog;
    SQL> alter database open;

    Disabling Archivelog Mode


    SQL> connect sys/password as sysdba
    SQL> shutdown immediate;
    SQL> startup mount;
    SQL> alter database noarchivelog;
    SQL> alter database open;

    Note  If  flashback database feature is enabled, first disable it before you disable database archiving.

    Displaying Archive Information


    Two ways can be used to display the mode of database


    SQL> select log_mode from v$database;
              LOG_MODE
              --------------------
              ARCHIVELOG


    SQL> archive log list;
              Database log mode                    Archive Mode
              Automatic archival                     Enabled
              Archive destination                     /u02/ora_archives/
              Oldest online log sequence         1
              Next log sequence to archive       2
              Current log sequence                  2

    Prior to Oracle Database 10g, it was also required to enable automatic archiving that tells Oracle to automatically create an archived redo log file when the online redo log file becomes full. With Oracle Database 10g onward, it is no longer required to do that by setting the archive_log_start parameter. The archive_log_start parameter is deprecated

    Where is my Alert log file?

    0 comments
    Beginning with Release 11g, the alert log file is written as XML formatted and as a text file (like in previous releases). The default location of both these files is the new ADR home (Automatic Diagnostic Respository).

    The ADR is set by using the DIAGNOSTIC_DEST initialization parameter. If this parameter is omitted, then, the default location of ADR is, 'u01/oracle/product/ora11g/log' depending on your ORACLE_HOME setting.

    The location of an ADR home is given by the following path, which starts at the ADR base directory: ADR_BASE/diag/product_type/product_id/instance_id

    If environment variable ORACLE_BASE is not set, DIAGNOSTIC_DEST is set to ORACLE_HOME/log.


    Also use the script below to locate you alert file in sqlplus

    SQL> select * from v$diag_info;
    Within the ADR home directory are subdirectories:alert - The XML formatted alertlog
    trace - files and text alert.log file
    cdump - core files

    The XML formatted alert.log is named as 'log.xml'

    Script to find out if Archlog Files backed up in last 24 Hours

    0 comments
    To see if archived logs got backed up in last 24 hours and how many are still sitting on the disks, use the script below

    SELECT backedup||' out of  '||archived||' archive logs backed up'  "Archlog files backed up",
           ondisk "Archlog files on disk"
      FROM (select count(*) archived
              from v$archived_log where completion_time > sysdate - 1),
           (select count(*) backedup from v$archived_log
             where backup_count > 0
               and completion_time > sysdate - 1),
           (select count(*) ondisk from v$archived_log
             where archived = 'YES' and deleted  = 'NO');

    Keeping PL/SQL in Oracle Memory

    0 comments
    If an application calls a BIG pl/sql block into a memory, it may result in kicking out several other cached SQL statements because of LRU (least recently used) algorithm. Now the subsequent call will increase the 'reloads'. That's where the reserved area of shared pool comes in. This area is called Shared Pool Reserved Area which is set by SHARED_POOL_RESERVED_SIZE parameter. The size of the reserved pool can be up 50 % of the shared_pool_size.

    We can also get a help on properly setting the shared_pool_reserved_size  by querying the dynamic performance view called V$SHARED_POOL_RESERVED as below

    SQL>SELECT free_space,request_misses, request_failures
    2        FROM v$shared_pool_reserved;


    FREE_SPACE            REQUEST_MISSES        REQUEST_FAILURES
    -------------------------------------------------------------------------------------------------------
    37181672             0                                             1

     If you see the following then probably your reserved_pool_size is over congigured

    1. Request_misses shows constantly 0 or static
    2. The value shown in FREE_SPACE is more than 50 % of the shared_pool_size
    3. Any non-zero or steady increase size of REQUEST_FAILURE shows that reserved area is too small.
    We can use the below script to find out the size of shared_pool and see if the FREE_SPACE is more than 50 % of it.

    SQL> SELECT pool, sum(bytes) "SIZE"
      2  FROM v$sgastat
      3  WHERE pool = ’shared pool’
      4 GROUP BY pool;

    POOL              SIZE
    ----------- ---------------------
    shared pool  838860800

    From that we know that our free_space column value in v$SHARED_POOL_RESERVED is less than 50 % of the shared pool. So we are good here!

    Now the process of adding the  PL/SQL code permanently into the memory is call pinning. Once pinned, the PL/SQL code will remain in a portion of shared pool allocated by shared_pool_reserved parameter until the instance is bounced.

    Since, now we have the basic understanding of shared pool reserved area and reasons for its configuration, lets now configure it in two simple steps

    1.  Build DBMS_SHARED_POOL package as its not installed by default by running dbmspool.sql script

    SQL> @$ORACLE_HOME/rdbms/admin/dbmspool.sql

    2. Use the dbms_shared_pool two procedures (KEEP or UNKEEP) to pin the object in memory as below

    SQL> EXECUTE DBMS_SHARED_POOL.KEEP (‘PREOCEDURE_TO_BE_PINNED’);

    Once done you can verify your steps above by query the below mentioned view


    SQL> SELECT owner, name, type

      2  FROM v$db_object_cache
      3  WHERE kept = ’YES’;

    Oracle RMAN: Industry Standards & best practices for Stable/Reliable backups

    0 comments
    Following are some of the best practices that we can adopt in order to have must stable and reliable oracle backups
    1. Turn on block checking.

    Block checking is enabled as below
                                         
    SQL> show parameter db_block_checking

    NAME                                 TYPE VALUE
    ------------------------------------ ---- ---------
    db_block_checking                 string FALSE
                                         
    SQL> alter system set db_block_checking = true scope=both;

    When set to 'TRUE' this allows oracle to detect early presence of corrupt blocks in the database.This has a slight performance overhead but can detect corruption caused by underlying disk, storage system, or I/O system problems.


    2.  Block Change Tracking tracking (incremental backups 10g & higher)

    Change Tracking File maintains  information that allows the RMAN incremental backup process to avoid reading data that has not yet been modified since the last backup. When Block Change Tracking is not used, all blocks must be read to determine if they have been modified since the last backup.


    SQL> alter database enable block change tracking using file '/u01/oradata/chg_trcing/chg_tracking.f';
    Once set the file can be queried from SQLPLUS as below

    SQL> SELECT filename, status, bytes  FROM v$block_change_tracking;
    for further information on incremental backups and block change tracking follow the below link
    http://docs.oracle.com/cd/B19306_01/backup.102/b14192/bkup004.htm


    3.  Archive log destination.

    Very important to have more than one archive log destinations. The reason is if an archivelog is corrupted or lost, by having multiple copies in multiple locations, the other logs will still be available and could be used.

    This is how an another archive log location can be added to the database

    SQL> alter system set log_archive_dest_2='location=/new/location/archive2' scope=both;
    4. Duplex redo log groups and members

    If an online log is deleted or becomes corrupt, you will have another member that can be used to recover if required.

    SQL> alter database add logfile member '/new/location/redo21.log' to group 1;

    Below SQL can be used to find out the number of members in the group


    SQL> SELECT a.group#, count(a.member) FROM v$logfile a, v$log b WHERE a.group# = b.group# group by a.group#  order by 1;

        GROUP# COUNT(A.MEMBER)
    ---------- ---------------
             1               2
             2               2
             3               2
             4               2
             5               2
             6               2
             7               2



    5.  RMAN  CHECK LOGICAL option.

    While taking backups with RMAN, using 'check logical ' option checks the  logical corruption within a block, in addition to the normal checksum verification. This is the best way to ensure that you will get a good backup.

    RMAN> backup check logical database plus archivelog delete input;

    for further information, see the below link

    http://docs.oracle.com/cd/B28359_01/backup.111/b28270/rcmvalid.htm

    6. Test the backups.

    Use 'Validate' command to test your backups. This will do everything except actually restore the database. This is the best method to determine if your backup is good and usable before being in a situation where it is critical and issues exist.
    RMAN> restore validate database;
    See below for more information
    http://docs.oracle.com/cd/B28359_01/backup.111/b28270/rcmvalid.htm

    7. When using RMAN have each datafile in a single backup piece

    When doing a partial restore RMAN must read through the entire piece to get the datafile/archivelog requested. The smaller the backup piece the quicker the restore can complete. This is especially relevent with tape backups of large databases or where the restore is only on individual / few files.

    However, very small values for filesperset will also cause larger numbers of backup pieces to be created, which can reduce backup performance and increase processing time for maintenance operations. So those factors must be weighed against the desired restore performance.


    RMAN> backup database filesperset 1 plus archivelog delete input;

    8. Maintain your RMAN catalog/controlfile

    Choose your retention policy carefully. Make sure that it complements your tape subsystem retention policy, requirements for backup recovery strategy. If not using a catalog, ensure that your CONTROL_FILE_RECORD_KEEP_TIME parameter matches your retention policy.


    SQL> alter system set control_file_record_keep_time=31 scope=both;
    This will keep 31 days of backup records in the control file.

    For more details :
    BASH-DBA: Relation between RMAN retention period and ...
    Note 461125.1 .
    9. Control file backup

    Ensure autobackup parameter in RMAN is always set to 'ON'.This will ensure that you always have an up to date controlfile available that has been taken at the end of the current backup, rather then during the backup itself.


    RMAN> configure controlfile autobackup on;
    Also, keep your backup logs. These logs contain parameters for your tape access, locations on controlfile backups that can be utilized if complete loss occurs.
    10. Test your recovery


    During a recovery situation this will let you know how the recovery will go without
    actually doing it, and can avoid having to restore source datafiles again.

    SQL> recover database test;

    11. In RMAN backups do not specify 'delete all input' when backing up archivelogs

    REASON: Delete all input' will backup from one destination then delete both copies of the
    archivelog where as 'delete input' will backup from one location and then delete what has
    been backed up. The next backup will back up those from location 2 as well as new logs
    from location 1, then delete all that are backed up. This means that you will have the
    archivelogs since the last backup available on disk in location 2 (as well as backed up
    once) and two copies backup up prior to the previous backup.

    See 
    Note 443814.1 Managing multiple archive log destinations with RMAN for details.


    Oracle Data Guard : Synchronous vs. Asynchronous Redo Transport

    1 comments
    Data Guard Redo Transport Services coordinate the transmission of redo from a primary database
    to the standby database. While LGWR process in Primary database is writing redo to its Online Redo Log files (ORL), a separate Data Guard process called the Log Network Server (LNS) is reading from
    the redo buffer in SGA and passes redo to Oracle Net Services for transmission to the standby
    database.

    Redo records transmitted by the LNS are received at the standby database by another Data Guard process called the Remote File Server (RFS) that writes it to a sequential file called a standby redo log file (SRL).

    Synchronous Redo Transport

    Its also called “zero data loss” method as the LGWR is not allowed to acknowledge a commit has succeeded until the LNS confirms that the redo needed to recover the transaction has been written to disk at the standby site.

    So that's how it works

    1. when user performs commits. The LGWR reads the redo record from the log buffer, writes it to the online redo log file, and waits for confirmation from the LNS.

    2. The LNS reads the same redo record from the log buffer and transmits it to the standby database using Oracle Net Services. The RFS receives the redo at the standby database and writes it to a standby redo log file.

    3. When the RFS receives a write-complete from the disk, it transmits an acknowledgment back to the LNS process on the primary database, which in turn notifies the LGWR that transmission is complete. The LGWR then sends a commit acknowledgment to the user.

    see the diagram below

    Asynchronous Redo Transport


    Asynchronous transport (ASYNC) LGWR  process does not wait for the acknowledgment from the LNS. This creates a near zero performance impact on the primary database regardless of the distance between primary and standby locations

    This behaviour of  ASYNC transport enables the primary database to buffer a large amount of redo,
    called a transport lag, without terminating transmission or impacting availability. Now the problem is if a failure destroys the primary database before any transport lag is reduced to zero, any committed transactions that are a part ofthe transport lag will be lost.

    The LGWR will continue to acknowledge commit success to the user even if limited bandwidth prevents the redo of previous transactions from being sent to the standby database immediately.

    LNS Behaviour when redo log is flushed 

    If the LNS is unable to keep pace and the log buffer is recycled before the redo can be transmitted to the standby, the LNS automatically transitions to reading and sending from the ORL (Data Guard 11g onward). Once the LNS is Once the LNS is caught up, it automatically transitions back to reading/sending directly from the log buffer. This is shown in the below diagram.


    source : Oracle documentation, oracle dataguard 11g hand book.

    Compare Structures of Two Tables in Oracle

    0 comments
    There are cases where we want to compare the structures of two tables and alter the first table structure as per the second table.

    I have created the following script to compare two tables structure and to generate the ALTER commands which will sync structure of 'dest_table' table as per the structure of 'src_table'.

    set serveroutput on
    
    declare
      l_str_size varchar2(100);
      l_str_query varchar2(2000);
      l_default1 varchar(4000);
      l_default2 varchar(4000);    
      p_dest_table varchar2(30); 
      p_src_table varchar2(30);
    begin
      p_dest_table := UPPER('&dest_table');
      p_src_table := UPPER('&src_table');
      for c in
      (
        select * from
          (select table_name t1, column_name c1, data_type dt1 , nvl(data_precision,data_length) dp1, 
          data_scale ds1, NULLABLE n1, DATA_DEFAULT d1 from user_tab_columns 
          where table_name = p_dest_table) dest
          FULL OUTER JOIN
          (select table_name t2, column_name c2, data_type dt2, nvl(data_precision,data_length) dp2, 
          data_scale ds2, NULLABLE n2, DATA_DEFAULT d2 from user_tab_columns 
          where table_name = p_src_table) src
          on c1 = c2
      )
      loop
        l_default1 := regexp_replace(c.d1,'[[:space:]]');
        l_default2 := regexp_replace(c.d2,'[[:space:]]');
        
        -- column altered
        if c.c1 is not null and c.c2 is not null then
          l_str_query := 'xyz';
          if c.dt1 <> c.dt2 or nvl(c.dp1,'-999') <> nvl (c.dp2,'-999') 
          or  nvl(c.ds1,'-999') <> nvl (c.ds2,'-999') or c.n1 <> c.n2 
          or nvl(l_default1,'xyz') <> nvl(l_default2,'xyz') then
            l_str_size := '(';
            if c.dp2 is not null then
              l_str_size :=l_str_size || c.dp2;
            end if;
            if c.ds2 is not null then
              l_str_size :=l_str_size || ',' || c.ds2;
            end if;
            l_str_size := l_str_size || ')';    
            l_str_query := 'alter table ' || p_dest_table || ' modify ' || c.c2 || ' ' || c.dt2;
            if l_str_size <> '()' and c.dt2 <> 'DATE' then
              l_str_query := l_str_query || l_str_size;
            end if;
            if l_default2 is not null then
              l_str_query := l_str_query || ' default ' ||  l_default2;
            end if;                
            if c.n2 = 'N' and  c.n1 = 'Y' then
              l_str_query := l_str_query || ' not null enable novalidate';
            end if;
            if c.n2 = 'Y' and  c.n1 = 'N' then
              l_str_query := l_str_query || ' null';
            end if;
          end if;
          if l_str_query <> 'xyz' then
            dbms_output.put_line(l_str_query || ';');
          end if;
        end if;
        
        -- column added
        if c.c1 is null and c.c2 is not null then
          l_str_size := '(';
          if c.dp2 is not null then
            l_str_size :=l_str_size || c.dp2;
          end if;
          if c.ds2 is not null then
            l_str_size :=l_str_size || ',' || c.ds2;
          end if;
          l_str_size := l_str_size || ')';            
          l_str_query := 'alter table ' || p_dest_table || ' add ' || c.c2 || ' ' || c.dt2;
          if l_str_size <> '()' and c.dt2 <> 'DATE' then
            l_str_query := l_str_query || l_str_size;
          end if;
          if l_default2 is not null then
            l_str_query := l_str_query || ' default ' ||  l_default2;
          end if;            
          if c.n2 = 'N' then
            l_str_query := l_str_query || ' not null';
          end if;
          dbms_output.put_line(l_str_query || ';');
        end if;        
        
        -- column deleted
        if c.c1 is not null and c.c2 is null then
          l_str_query := 'alter table ' || p_dest_table || ' drop column ' || c.c1;
          dbms_output.put_line(l_str_query || ';');
        end if;            
      end loop;
    end;
    /
    

    This script will take care of following Table Structure Mismatch
    - Columns to be Added
    - Columns to be Dropped
    - Columns to be Resized
    - Columns to be marked as NULL or Not NULL
    - Columns to be modified for default Value

    Oracle: Query to find the 10 Largest Objects in DB

    0 comments
    SELECT * FROM
    (
    select
        SEGMENT_NAME,
        SEGMENT_TYPE,
        BYTES/1024/1024/1024 GB,
        TABLESPACE_NAME
    from
        dba_segments
    order by 3 desc 
    ) WHERE
    ROWNUM <= 10;


    col owner format a15
    col segment_name format a30
    col segment_type format a15
    col mb format 999,999,999
    select owner
    , segment_name
    , segment_type
    , mb
    from (
    select owner
    , segment_name
    , segment_type
    , bytes / 1024 / 1024 "MB"
    from dba_segments
    order by bytes desc
    )
    where rownum < 11
    /

    Oracle Locks

    0 comments
    Oracle provides many areas of locking:
    • Locks and Oracle
    • Lock management and escalation with Oracle
    • Lock management in an Oracle RAC environment
    • Enhancements to locks with Oracle
    • Tips for resolving lock issues with Oracle
    • Avoiding deadlock conditions with Oracle
    Oracle locks have been around a long time since the inception of the first major database release with the Oracle database environment.  What is the purpose of a lock within the Oracle database? Locks function as the primary mechanism to provide for data concurrency and data consistency within the database.
    It allows for multiple users to access the data simultaneously while providing a consistent view of data including any changes made by each user's transaction and that of other user transactions made to and against the data within Oracle. Furthermore, locks prevent errors in read and write consistency as part of the relational database ACID model. The database ACID model refers to Atomic, Consistency, Isolation, and Durability. To further explain what ACID means in terms of Oracle and other relational database models, the following explanation illustrates.
    Atomicity:
    For each transaction within the Oracle database, all of the units of work for a transaction must either be all or nothing. In other words, the transaction must be completed or else it must be undone or rolled back. Undo and rollback provide these functions with transactions in concert with locking and latching mechanisms.
    Consistency:
    Every transaction is required to preserve the integrity constraints which function as part of the declared consistency rules within the Oracle database. Database constraints are the business rules that provide for consistency.
    Isolation:
    This means that multiple transactions cannot interfere with one another at the same time. Results that are performed in flight, i.e. uncommitted transactions, are not visible to other transactions until a commit phase is executed and completed. Locks provide the mechanism for the isolation phase within the ACID model for Oracle database transactions.
    For example, if Sally user locks table A with an exclusive lock, then user Bill will not be able to update the rows in that table until Sally has completed her transaction on that table. If locks did not exist within Oracle, there would be many problems with phantom reads and writes. This concurrency control ensures that all transactions within Oracle are executed safely and according to these rules so that no committed transactions are lost while in the event of a rollback undo operation to abort transactions.
    Durability:
    Durability is provided for by the Oracle database engine so that completed transactions are maintained and not lost in the future. Oracle protects against lost transactions by use of committed transactions stored within the undo/rollback segments and undo tablespaces within the Oracle database engine.

    Oracle has several views for showing lock status, some of which show the username:
    • DBA_BLOCKERS – Shows non-waiting sessions holding locks being waited-on
    • DBA_DDL_LOCKS – Shows all DDL locks held or being requested
    • DBA_DML_LOCKS  - Shows all DML locks held or being requested
    • DBA_LOCK_INTERNAL – Displays 1 row for every lock or latch held or being requested with the username of who is holding the lock 
    • DBA_LOCKS  - Shows all locks or latches held or being requested
    • DBA_WAITERS  - Shows all sessions waiting on, but not holding waited for locks
    **********Query for checking object level locks*************

    select   c.owner,c.object_name,c.object_type,b.sid,b.serial#,b.status,b.osuser,b.machine from gv$locked_object a ,gv$session b,dba_objects c where b.sid = a.session_id and a.object_id = c.object_id;
    #########################################################################

    ***********Query to Identify locks and Transaction ID's *******************
    select username,
    v$lock.sid,
    trunc(id1/power(2,16)) rbs,
    bitand(id1, to_number('ffff', 'xxxx'))+0 slot,
    id2 seq,
    lmode,
    request
    from v$lock, v$session
    where v$lock.type = 'TX'
    and v$lock.sid = v$session.sid
    and v$session.username = username;
    **************Query to Identify who is blocking whom ********************
    select (select username from v$session where sid=a.sid) blocker,
    a.sid,
    ' is blocking ',
    (select username from v$session where sid=b.sid) blockee,
    b.sid
    from v$lock a, v$lock b
    where a.block = 1
    and b.request > 0
    and a.id1 = b.id1
    and a.id2 = b.id2;
    **************Query to Identify Locks*******************************
    select * from dba_ddl_locks;

    Script for Hidden Parameters

    0 comments
    SET VERIFY OFF
    COLUMN parameter      FORMAT a37
    COLUMN description    FORMAT a30 WORD_WRAPPED
    COLUMN session_value  FORMAT a10
    COLUMN instance_value FORMAT a10

    SELECT a.ksppinm AS parameter,
           a.ksppdesc AS description,
           b.ksppstvl AS session_value,
           c.ksppstvl AS instance_value
    FROM   x$ksppi a,
           x$ksppcv b,
           x$ksppsv c
    WHERE  a.indx = b.indx
    AND    a.indx = c.indx
    AND    a.ksppinm LIKE '/_%' ESCAPE '/'
    AND    a.ksppinm = DECODE(LOWER('&1'), 'all', a.ksppinm, LOWER('&1'))
    ORDER BY a.ksppinm;

    Oracle RAC Basic

    0 comments
    What is Cluster?
    Cluster consists of two or more independent nodes. Cluster software hides structure of nodes. Due to cluster software all nodes are acting as single server.

    What is Real Application Cluster?
    It is component of Oracle for managing two or more instances on different node which are sharing single database. RAC software manages data access and makes consistent image of database.

    What is Node?
    Each node contains separate CPU and memory and self contained server in cluster. It contains single instance of RAC database.

    What is Interconnect?
    Using cluster interconnect each node communicates messages to other nodes. In short using interconnect all nodes are talking to each other. Interconnect transfers all messages of database from all connected nodes.

    What is Shared Disk?
    Oracle real application cluster database must be accessible from all connected nodes (Instances). Due to this database must be on shared disk which is accessed by all nodes. RAW device file system available in Unix/Linux and unformatted disk partition available in Windows for making shared disk.

    What is Cluster Manager?
    Cluster Manager manages and monitoring connected nodes. It regulates messages and activity of nodes in cluster.

    What is Oracle Cluster file system (OCFS)?
    OCFS is shared file system and made by Oracle itself for Oracle Real Application Cluster. It allows to accessing single Oracle Home for all nodes. Without using OCFS we should need to install separate Oracle Home on each nodes in Cluster.

    What is Oracle Clusterware?
    In previous version of oracle (Oracle 9i) it is called as Cluster Manager. Oracle clusterware monitors all components like instances and listeners. There are two components in Oracle clusterware, those are Voting Disk and OCR.

    What is Voting Disk?
    Voting Disk is shared disk component. Information of shared storage & nodes reside in Voting Disk. It is accessed by the all nodes during cluster operations. Every node pings Voting Disk, if will be failing to ping cluster immediate serves as communication failure & the node is evicted from cluster.

    What is OCR?
    OCR means Oracle Cluster Registry. It stores cluster configuration information. It is also shared disk component. It must be accessed by all nodes in cluster environment.It also keeps information of Which database instance run on which nodes and which service runs on which database.The daemon OCSSd manages the configuration info in OCR and maintains the changes to cluster in the registry.

    Oracle: Query to find the 10 Largest Objects in DB

    0 comments
    SELECT * FROM
    (
    select
        SEGMENT_NAME,
        SEGMENT_TYPE,
        BYTES/1024/1024/1024 GB,
        TABLESPACE_NAME
    from
        dba_segments
    order by 3 desc 
    ) WHERE
    ROWNUM <= 10

    Oracle: DBMS_STATS Gather Statistics of Schema, Tables, Indexes

    2 comments
    In this post I'll try to cover all sorts of statistics in Oracle, I encourage you to read the full post cause I'm sure you will find a new information you may read it for the first time.

    ###############################
    Database | Schema | Table | Index Statistics
    ###############################

    Gather Database Stats:
    ====================
    SQL> EXEC DBMS_STATS.GATHER_DATABASE_STATS(
                    ESTIMATE_PERCENT=>100,METHOD_OPT=>'FOR ALL
                    COLUMNS SIZE SKEWONLY',
    CASCADE => TRUE,
    degree => 4,
    OPTIONS => 'GATHER STALE',
    GATHER_SYS => TRUE
    STATTAB => PROD_STATS);

    CASCADE => TRUE :Gather statistics on the indexes as well. If not used Oracle will determine whether
                                     to collected or not.
    DEGREE => 4 :Degree of parallelism.
    OPTIONS =>'GATHER' :Gathers statistics on all objects in the schema.
    =>'GATHER AUTO' :Oracle determines which objects need new statistics, and determines how to
                                         gather those statistics.
    =>'GATHER STALE':Gathers statistics on stale objects. will return a list of stale objects.
    =>'GATHER EMPTY':Gathers statistics on objects have no statistics.will return a list of no stats
                                          objects.
    =>'LIST AUTO' : Returns a list of objects to be processed with GATHER AUTO.
    =>'LIST STALE': Returns a list of stale objects as determined by looking at the
                                          *_tab_modifications views.
    =>'LIST EMPTY': Returns a list of objects which currently have no statistics.
    GATHER_SYS => TRUE :Gathers statistics on the objects owned by the 'SYS' user.
    STATTAB => PROD_STATS :Table will save the current statistics. see SAVE & IMPORT
                                               STATISTICS section -last third in this post-.

    Note: All parameters above are valid for all stats kind (schema,table,..) except Gather_SYS.

    For faster execution:
    ------------------
    SQL> EXEC DBMS_STATS.GATHER_DATABASE_STATS(ESTIMATE_PERCENT=>DBMS_STATS.AUTO_SAMPLE_SIZE,degree => 8);

    What's new?
    ESTIMATE_PERCENT=>DBMS_STATS.AUTO_SAMPLE_SIZE => Let Oracle estimate skewed
    values always gives excellent results.(DEFAULT).
    Removed "METHOD_OPT=>'FOR ALL COLUMNS SIZE SKEWONLY'" => As histograms is not
    recommended to be gathered on all columns.
    Removed "cascade => TRUE" To let Oracle determine whether index statistics to be collected or not.
    Doubled "degree => 8" but this depends on the number of CPUs on the machine and accepted CPU
    overhead during gathering DB statistics.

    This task became an automated task starting from 10g, To check the status of that task:
    SQL> select * from dba_autotask_client where client_name = "auto optimizer stats collection" ;


    Gather SCHEMA Stats:
    =====================
    SQL> Exec DBMS_STATS.GATHER_SCHEMA_STATS (
           ownname =>'SCOTT',
           estimate_percent=>10,
           degree=>1,
           cascade=>TRUE,
           options=>'GATHER STALE');


    Gather TABLE Stats:
    ===================
    Check table statistics date:
    SQL> select table_name, last_analyzed from user_tables where table_name='T1';

    SQL> Begin DBMS_STATS.GATHER_TABLE_STATS (
    ownname => 'SCOTT',
    tabname => 'EMP',
    degree => 2,
    cascade => TRUE,
    METHOD_OPT => 'FOR COLUMNS SIZE AUTO',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE);
         END;
         /

    CASCADE => TRUE :Gather statistics on the indexes as well. If not used Oracle will determine whether to collect it or not.
    DEGREE => 2 :Degree of parallelism.
    options =>'GATHER' :Gathers statistics on all objects in the schema.
    =>'GATHER AUTO' :Oracle determines which objects need new statistics, and determines how to
                                               gather those statistics.
    =>'GATHER STALE':Gathers statistics on stale objects. will return a list of stale objects.
    =>'GATHER EMPTY':Gathers statistics on objects have no statistics.will return a list of no stats objects.
    =>'LIST AUTO' : Returns a list of objects to be processed with GATHER AUTO.
    =>'LIST STALE': Returns a list of stale objects as determined by looking at the
                                               *_tab_modifications views.
    =>'LIST EMPTY': Returns a list of objects which currently have no statistics.
    ESTIMATE_PERCENT => DBMS_STATS.AUTO_SAMPLE_SIZE :(DEFAULT) Auto set the sample size % for skew(distinct) values (accurate and faster than setting a manual sample size).
    METHOD_OPT=>  : For gathering Histograms:
     FOR COLUMNS SIZE AUTO : you can specify one column between "" instead of all
                                                             columns.
     FOR ALL COLUMNS SIZE REPEAT : Prevent deletion of histograms and collect it only for
                                                                            columns already have histograms.
     FOR ALL COLUMNS  : collect histograms on all columns.
     FOR ALL COLUMNS SIZE SKEWONLY : collect histo for columns have skewed value                                                                               should test skewness first>.
     FOR ALL INDEXED COLUMNS : collect histograms for columns have indexses only.

    Gather Index Stats:
    ==================
    SQL> exec DBMS_STATS.GATHER_INDEX_STATS(
    ownname => 'SCOTT',
    indname => 'EMP_I',
    estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE);



    ###################
    Fixed OBJECTS Statistics
    ###################

    What are Fixed objects:
    ---------------------
    -Fixed objects are the x$ tables (been loaded in SGA during startup) on which V$ views are built (V$SQL etc.).
    -If the statistics are not gathered on fixed objects, the Optimizer will use predefined default values for the statistics. These defaults may lead to inaccurate execution plans.
    -Statistics on fixed objects are not being gathered automatically nor within gathering DB stats.

    How frequent to gather stats on fixed objects?
    ------------------------------------------
    Only one time for a representative workload unless you've one of these cases:

    -After a major database or application upgrade.
    -After implementing a new module.
    -After changing the database configuration. e.g. changing the size of memory pools (sga,pga,..).
    -Poor performance/Hang encountered while querying dynamic views e.g. V$ views.


    Note:
    -It's recommended to Gather the fixed object stats during peak hours (system is busy) or after the peak hours but the sessions are still connected (even if they idle), to guarantee that the fixed object tables been populated and the statistics well represent the DB activity.
    -also note that performance degradation may be experienced while the statistics are gathering.
    -Having no statistics is better than having a non representative statistics.

    How to gather stats on fixed objects:
    ------ ------------------------------

    Firstly Check the last analyzed date:
    ------ --------------------------
    select OWNER, TABLE_NAME, LAST_ANALYZED from dba_tab_statistics where table_name='X$KGLDP';

    Secondly Export the current fixed stats in a table: (in case you need to revert back)
    ------ - --------------------------------------
    EXEC DBMS_STATS.CREATE_STAT_TABLE('OWNER','STATS_TABLE_NAME','TABLESPACE_NAME');

    EXEC dbms_stats.export_fixed_objects_stats(stattab=>'STATS_TABLE_NAME',statown=>'OWNER');

    Thirdly Gather the fixed objects stats:
    ------  ---------------------------
    exec dbms_stats.gather_fixed_objects_stats;

    Note In case of reverting back to the old stats:
    ---- ----------------------------------------
    In case you experienced a bad performance on fixed tables after gathering the new statistics:

    exec dbms_stats.delete_fixed_objects_stats(); 
    exec DBMS_STATS.import_fixed_objects_stats(stattab =>'STATS_TABLE_NAME',STATOWN =>'OWNER');



    #################
    SYSTEM STATISTICS
    #################

    What is system statistics:
    -------------------------
    System statistics are statistics about CPU speed and IO performance, it enables the CBO to
    effectively cost each operation in an execution plan. Introduced in Oracle 9i.

    Why gathering system statistics:
    ------------------------------
    Oracle highly recommends gathering system statistics during a representative workload,
    ideally at peak workload time, in order to provide more accurate CPU/IO cost estimates to the optimizer.
    You only have to gather system statistics once.

    There are two types of system statistics (NOWORKLOAD statistics & WORKLOAD statistics):

    NOWORKLOAD statistics:
    --------------------------
    This will simulates a workload -not the real one but a simulation- and will not collect full statistics, it's less accurate than "WORKLOAD

    statistics" but if you can't capture the statistics during a typical workload you can use noworkload statistics.

    To gather noworkload statistics:

    SQL> execute dbms_stats.gather_system_stats();

    WORKLOAD statistics:
    ----------------------
    This will gather statistics during the current workload -which supposed to be representative of actual system I/O and CPU workload on the DB-.

    To gather WORKLOAD statistics:

    SQL> execute dbms_stats.gather_system_stats('start');

    Once the workload window ends after 1,2,3.. hours or whatever, stop the system statistics gathering:

    SQL> execute dbms_stats.gather_system_stats('stop');

    You can use time interval (minutes) instead of issuing start/stop command manually:

    SQL> execute dbms_stats.gather_system_stats('interval',60);

    Check the system values collected:
    -------------------------------
    col pname format a20
    col pval2 format a40
    select * from sys.aux_stats$;

    cpuspeedNW: Shows the noworkload CPU speed, in terms of the average number of CPU cycles per
                               second.
    ioseektim:  The sum of seek time, latency time, and OS overhead time.
    iotfrspeed: I/O transfer speed,tells the optimizer how fast the database can read data in a single read
                               request.
    cpuspeed:   Stands for CPU speed during a workload statistics collection.
    maxthr:        The maximum I/O throughput.
    slavethr:   Average parallel slave I/O throughput.
    sreadtim:   The Single Block Read Time statistic shows the average time for a random single block read.
    mreadtim:   The average time (seconds) for a sequential multiblock read.
    mbrc:       The average multiblock read count in blocks.

    According to Oracle, collecting workload statistics doesn't impose an additional overhead on your system.

    Delete system statistics:
    ---------------------
    SQL> execute dbms_stats.delete_system_stats();



    ####################
    Data Dictionary Statistics
    ####################

    Facts:
    -----
    >Dictionary tables are the tables owned by SYS and residing in the system tablespace.
    >Normally data dictionary statistics in 9i is not required unless performance issues are detected.
    >In 10g Statistics on the dictionary tables will be maintained via the automatic statistics gathering job run during the nightly maintenance window.

    If you choose to switch off that job for application schema consider leaving it on for the dictionary tables. You can do this by changing the value of AUTOSTATS_TARGET from AUTO to ORACLE using the procedure:

    SQL> Exec DBMS_STATS.SET_PARAM(AUTOSTATS_TARGET,'ORACLE'); 

    When to gather Dictionary statistics:
    ---------------------------------
    -After DB upgrades.
    -After creation of a new big schema.
    -Before and after big datapump operations.

    Check last Dictionary statistics date:
    ----------------------------------
    SQL> select table_name, last_analyzed from dba_tables where owner='SYS' and table_name like '%$' order by 2;

    Gather Dictionary Statistics:  
    -------------------------
    SQL> EXEC DBMS_STATS.GATHER_DICTIONARY_STATS; ->Will gather stats on 20% of SYS schema tables.
    or...
    SQL> EXEC DBMS_STATS.GATHER_SCHEMA_STATS ('SYS'); ->Will gather stats on 100% of SYS schema tables.
    or...
    SQL> EXEC DBMS_STATS.GATHER_DATABASE_STATS (gather_sys=>TRUE); ->Will gather stats on the whole DB+SYS schema.



    #############
    Extended Statistics "11g onwards"
    #############

    Extended statistics can be gathered on columns based on functions or column groups.

    Gather extended stats on column function:
    ===================================
    If you run a query having in the WHERE statement a function like upper/lower the optimizer will be off and index on that column will not be used:

    SQL> select count(*) from EMP where lower(ename) = 'scott';

    In order to make optimizer work with function based terms you need to gather extended stats:

    1-Create extended stats:
    >>>>>>>>>>>>>>>>>>>
    SQL> select dbms_stats.create_extended_stats('SCOTT','EMP','(lower(ENAME))') from dual;

    2-Gather histograms:
    >>>>>>>>>>>>>>>
    SQL> exec dbms_stats.gather_table_stats ('SCOTT','EMP', method_opt=> 'for all columns size skewonly');

    OR
    --
    *You can do it also in one Step:
    >>>>>>>>>>>>>>>>>>>>>>>>>

    SQL> Begin
         dbms_stats.gather_table_stats (
         ownname    => 'SCOTT',
         tabname    => 'EMP',
         method_opt => 'for all columns size skewonly for columns (lower(ENAME))'
         );
         end;

    To check the Existance of extended statistics on a table:
    ---------------------------------------------------
    SQL> select extension_name,extension from dba_stat_extensions where owner='SCOTT'and table_name = 'EMP';

    SYS_STU2JLSDWQAFJHQST7$QK81_YB (LOWER("ENAME"))

    Drop extended stats on column function:
    -------------------------------------
    SQL> exec dbms_stats.drop_extended_stats('SCOTT','EMP','(LOWER("ENAME"))');

    Gather extended stats on column group: -related columns-
    =================================
    Certain columns in a table that are part of a join condition (where statement  are correlated e.g.(country,state). You want to make the optimizer aware of this relationship between two columns and more instead of using separate statistics for each columns. By creating extended statistics on a group of columns, the Optimizer can determine a more accurate the relation between the columns are used together in a where clause of a SQL statement. e.g. columns like country_id and state_name the have a relationship, state like Texas can only be found in USA so the value of state_name are always influenced by country_id.
    If there are extra columns are referenced in the "WHERE statement  with the column group the optimizer will make use of column group statistics.

    1- create a column group:
    >>>>>>>>>>>>>>>>>>>>>
    SQL> select dbms_stats.create_extended_stats('SH','CUSTOMERS', '(country_id,cust_state_province)') from dual;

    2- Re-gather stats|histograms for table so optimizer can use the newly generated extended statistics:
    >>>>>>>>>>>>>>>>>>>>>>>
    SQL> exec dbms_stats.gather_table_stats ('SH','customers', method_opt=> 'for all columns size skewonly');

    OR
    --
    *You can do it also in one Step:
    >>>>>>>>>>>>>>>>>>>>>>>>>

    SQL> Begin
         dbms_stats.gather_table_stats (
         ownname    => 'SH',
         tabname    => 'CUSTOMERS',
         method_opt => 'for all columns size skewonly for columns (country_id,cust_state_province)'
         );
         end;

    Drop extended stats on column group:
    --------------------------------------
    SQL> exec dbms_stats.drop_extended_stats('SH','CUSTOMERS', '(country_id,cust_state_province)');



    ########
    Histograms
    ########

    What are Histograms?

    ------------------
    >Holds data about values within a column in a table for number of occurrences for a specific value/range.
    >Used by CBO to optimize a query to use whatever index Fast Full scan or table full scan.
    >Usually being used against columns have data being repeated frequently like country or city column.
    >gathering histograms on a column having distinct values (PK) is useless because values are not repeated.
    >Two types of Histograms can be gathered:
     >Frequency histograms: is when distinct values (buckets) in the column is less than 255 (# countries is always less than 254.

    Height balanced histograms: are similar to frequency histograms in their design, but distinct values  > 254

    See Example: http://aseriesoftubes.com/articles/beauty-and-it/quick-guide-to-oracle-histograms/

    - Collected by DBMS_STATS (which by default doesn't collect histograms, it deletes them if you didn't use the parameter).
    - Mainly being gathered on foreign key columns/columns in WHERE statement.
    - Helps in SQL multi-table joins.
    - Column histograms like statistics are being stored in data dictionary.
    - If application exclusively uses bind variables, Oracle recommends deleting any existing Oracle histograms and disabling Oracle histograms generation.


    Caution:
    – Do not create them on Columns that are not queried.
    – Do not create them on every column of every table.
    – Do not create them on PK of a table.

    Verify the existence of histograms:
    ----------------------------------
    SQL> select column_name,histogram from dba_tab_col_statistics where owner='SCOTT' and table_name='EMP';

    Creating Histograms:
    ----------------------
    e.g.

    SQL> Exec dbms_stats.gather_table_stats(
    ownname => '', 
    tabname => '', 
            estimate_percent => dbms_stats.auto_sample_size, 
    METHOD_OPT => 'FOR COLUMNS SIZE AUTO ');

    SQL> Exec dbms_stats.gather_schema_stats(
          ownname          => 'SCOTT', 
          estimate_percent => dbms_stats.auto_sample_size, 
          method_opt       => 'for all columns size auto', 
          degree           => 7);

    FOR COLUMNS SIZE AUTO  => Fastest. you can specify one column instead of all columns.
    FOR ALL COLUMNS SIZE REPEAT => to prevent deletion of histograms and collect it only for columns already have histograms.
    FOR ALL COLUMNS              => collect histograms on all columns .
    FOR ALL COLUMNS SIZE SKEWONLY => collect histograms for columns have skewed value .
    FOR ALL INDEXES COLUMNS       => collect histograms for columns have indexes.

    Note: For AUTO & SKEWONLY Oracle will decide whatever to create Histograms or not.

    Check existence of Histograms:

    SQL> select column_name, count(*) from dba_tab_histograms where table_name='SMFILECABINET' group by column_name;

    Drop Histograms: 11g
    -----------------
    e.g.
    SQL> Exec dbms_stats.delete_column_stats(ownname=>'SH', tabname=>'SALES', colname=>'PROD_ID', col_stat_type=> HISTOGRAM);

    Stop gathering Histograms: 11g
    e.g.
    SQL> Exec dbms_stats.set_table_prefs
         ('SH', 'SALES','METHOD_OPT', 'FOR ALL COLUMNS SIZE AUTO, FOR COLUMNS SIZE 1 PROD_ID');
    >Will continue to collect histograms as usual on all columns in the SALES table except for the PROD_ID column.

    Drop Histograms: 10g
    ----------------
    e.g.
    SQL> exec dbms_stats.delete_column_stats( user, 'T', 'USERNAME' );



    ##################################
    Save/IMPORT & RESTORE STATISTICS:
    ##################################
    ===================
    Export /Import Statistics:
    ===================
    In this way statistics will be exported into table then imported later from that table.

    1-Create STATS TABLE:
    -  ----------------------
    SQL> Exec dbms_stats.create_stat_table (ownname => 'SYSTEM', stattab => 'prod_stats', tblspace => 'USERS'); 

    2-Export the statistics to the STATS table:
    ------------------------------------------
    For Database stats:
    SQL> Exec dbms_stats.export_database_stats (statown => 'SYSTEM', stattab => 'prod_stats');

    For System stats:
    SQL> Exec dbms_stats.export_SYSTEM_stats (statown => 'SYSTEM', stattab => 'prod_stats');

    For Dictionary stats:
    SQL> Exec dbms_stats.export_Dictionary_stats (statown => 'SYSTEM', stattab => 'prod_stats');

    For Fixed Tables stats:
    SQL> Exec dbms_stats.export_FIXED_OBJECTS_stats (statown => 'SYSTEM', stattab => 'prod_stats');

    For Schema stas:
    SQL> EXEC DBMS_STATS.EXPORT_SCHEMA_STATS('ORIGINAL_SCHEMA' ,'STATS_TABLE',NULL,'STATS_TABLE_OWNER');

    For Table:
    SQL> Conn scott/tiger
    SQL> Exec dbms_stats.export_TABLE_stats (ownname => 'SCOTT',tabname => 'EMP',stattab => 'prod_stats');

    For Index:
    SQL> Exec dbms_stats.export_INDEX_stats (ownname => 'SCOTT',indname => 'PK_EMP',stattab => 'prod_stats');

    For Column:
    SQL> Exec dbms_stats.export_COLUMN_stats (ownname =>'SCOTT',tabname=>'EMP',colname=>'EMPNO',stattab=>'prod_stats');

    3-Import the statistics from PROD_STATS table to the dictionary:
    --------------------------------------------------------------------
    For Database stats:
    SQL> Exec DBMS_STATS.IMPORT_DATABASE_STATS (stattab => 'prod_stats',statown => 'SYSTEM');

    For System stats:
    SQL> Exec DBMS_STATS.IMPORT_SYSTEM_STATS (stattab => 'prod_stats',statown => 'SYSTEM');

    For Dictionary stats:
    SQL> Exec DBMS_STATS.IMPORT_Dictionary_STATS (stattab => 'prod_stats',statown => 'SYSTEM');

    For Fixed Tables stats:
    SQL> Exec DBMS_STATS.IMPORT_FIXED_OBJECTS_STATS (stattab => 'prod_stats',statown => 'SYSTEM');

    For Schema stats:
    SQL> Exec DBMS_STATS.IMPORT_SCHEMA_STATS (ownname => 'SCOTT',stattab => 'prod_stats',statown => 'SYSTEM');

    For Table stats and it's indexes:
    SQL> Exec dbms_stats.import_TABLE_stats ( ownname => 'SCOTT', stattab => 'prod_stats', tabname => 'EMP');

    For Index:
    SQL> Exec dbms_stats.import_INDEX_stats ( ownname => 'SCOTT', stattab => 'prod_stats', indname => 'PK_EMP');

    For COLUMN:
    SQL> Exec dbms_stats.import_COLUMN_stats (ownname =>'SCOTT',tabname=>'EMP',colname=>'EMPNO',stattab=>'prod_stats');

    4-Drop Stat Table:
    -------------------
    SQL> Exec dbms_stats.DROP_STAT_TABLE (stattab => 'prod_stats',ownname => 'SYSTEM');


    ==============
    Restore statistics: -From Dictionary-
    ==============
    Old statistics are saved automatically in SYSAUX for 31 day.

    Restore Dictionary stats as of timestamp:
    -----------------------------------------
    SQL> Exec DBMS_STATS.RESTORE_DICTIONARY_STATS(sysdate-1);

    Restore Database stats as of timestamp:
    --------------------------------------
    SQL> Exec DBMS_STATS.RESTORE_DATABASE_STATS(sysdate-1);

    Restore SYSTEM stats as of timestamp:
    --------------------------------------
    SQL> Exec DBMS_STATS.RESTORE_SYSTEM_STATS(sysdate-1);

    Restore FIXED OBJECTS stats as of timestamp:
    -----------------------------------------------
    SQL> Exec DBMS_STATS.RESTORE_FIXED_OBJECTS_STATS(sysdate-1);

    Restore SCHEMA stats as of timestamp:
    ---------------------------------------
    SQL> Exec dbms_stats.restore_SCHEMA_stats(ownname=>'SYSADM',AS_OF_TIMESTAMP=>sysdate-1);
    OR:
    SQL> Exec dbms_stats.restore_schema_stats(ownname=>'SYSADM',AS_OF_TIMESTAMP=>'20-JUL-2008 11:15:00AM');

    Restore Table stats as of timestamp:
    -----------------------------------
    SQL> Exec DBMS_STATS.RESTORE_TABLE_STATS(ownname=>'SYSADM', tabname=>'T01POHEAD',AS_OF_TIMESTAMP=>sysdate-1);

    =====
    FACTS:
    =====

    To Check current Stats history retention period (days):
    ---------------------------------------------------
    SQL> select dbms_stats.get_stats_history_retention from dual;
    SQL> select dbms_stats.get_stats_history_availability from dual;

    To modify current Stats history retention period (days):
    ---------------------------------------------------
    SQL> Exec dbms_stats.alter_stats_history_retention(60);

    Purge statistics older than 10 days:
    -------------------------------
    SQL> Exec DBMS_STATS.PURGE_STATS(SYSDATE-10);


    Procedure To claim space after purging statstics:
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    Space will not be claimed automatically when you purge stats, you must claim it manually using this procedure:

    Check Stats tables size:
    >>>>>>
    col Mb form 9,999,999
    col SEGMENT_NAME form a40
    col SEGMENT_TYPE form a6
    set lines 120
    select sum(bytes/1024/1024) Mb, segment_name,segment_type from dba_segments
    where  tablespace_name = 'SYSAUX'
    and segment_name like 'WRI$_OPTSTAT%'
    and segment_type='TABLE'
    group by segment_name,segment_type order by 1 asc
    /

    Check Stats indexes size:
    >>>>>>
    col Mb form 9,999,999
    col SEGMENT_NAME form a40
    col SEGMENT_TYPE form a6
    set lines 120
    select sum(bytes/1024/1024) Mb, segment_name,segment_type from dba_segments
    where  tablespace_name = 'SYSAUX'
    and segment_name like '%OPT%'
    and segment_type='INDEX'
    group by segment_name,segment_type order by 1 asc
    /

    Move Stats tables in same tablespace:
    >>>>>>
    select 'alter table '||segment_name||'  move tablespace SYSAUX;' from dba_segments where tablespace_name = 'SYSAUX'
    and segment_name like '%OPT%' and segment_type='TABLE'
    /

    Rebuild Stats indexes:
    >>>>>>
    select 'alter index '||segment_name||'  rebuild online;' from dba_segments where tablespace_name = 'SYSAUX'
    and segment_name like '%OPT%' and segment_type='INDEX'
    /

    Check for un-usable indexes:
    >>>>>>
    select  di.index_name,di.index_type,di.status  from  dba_indexes di , dba_tables dt
    where  di.tablespace_name = 'SYSAUX'
    and dt.table_name = di.table_name
    and di.table_name like '%OPT%'
    order by 1 asc
    /


    Delete Statistics:
    =============
    For Database stats:
    SQL> Exec DBMS_STATS.DELETE_DATABASE_STATS ();

    For System stats:
    SQL> Exec DBMS_STATS.DELETE_SYSTEM_STATS ();

    For Dictionary stats:
    SQL> Exec DBMS_STATS.DELETE_DICTIONARY_STATS ();

    For Fixed Tables stats:
    SQL> Exec DBMS_STATS.DELETE_FIXED_OBJECTS_STATS ();

    For Schema stats:
    SQL> Exec DBMS_STATS.DELETE_SCHEMA_STATS ('SCOTT');

    For Table stats and it's indexes:
    SQL> Exec dbms_stats.DELETE_TABLE_stats (ownname=>'SCOTT',tabname=>'EMP');

    For Index:
    SQL> Exec dbms_stats.DELETE_INDEX_stats ( ownname => 'SCOTT',indname => 'PK_EMP');

    For COLUMN:
    SQL> Exec dbms_stats.DELETE_COLUMN_stats (ownname =>'SCOTT',tabname=>'EMP',colname=>'EMPNO');


    Note: This procedure can be rollback by restoring STATS using DBMS_STATS.RESTORE_ procedure.


    Pending Statistics:  "11g onwards"
    =============
    Switch on pending statistics:
    SQL> Exec DBMS_STATS.SET_GLOBAL_PREFS('PENDING','TRUE');

    Gather 11g statistics:
    SQL> Exec DBMS_STATS.GATHER_TABLE_STATS('sh','SALES');

    Test your critical SQL statement with the pending stats:
    SQL> Alter session set optimizer_use_pending_statistics=TRUE;

    When proven, publish the pending statistics:
    SQL> Exec DBMS_STATS.PUBLISH_PENDING_STATS();

    Copyright © ORACLE ONLINE DBA
    Developed By Pavan Yennampelli