rem 
rem $Header: utlestat.sql 17-apr-98.15:26:01 kquinn Exp $ estat.sql 
rem 
Rem Copyright (c) 1988, 1996, 1998 by Oracle Corporation
Rem NAME
REM    UTLESTAT.SQL
Rem  FUNCTION
Rem    This script will generate a report (in "report.txt") which will contain
Rem    usefull information for performance monitoring.  In particular
Rem    information from v$sysstat, v$latch, and v$rollstat.
Rem  NOTES
Rem    Don't worry about errors during "drop table"s, they are normal.
Rem  MODIFIED
Rem     khailey    03/15/99 -  594266: Correct per logon stats, add fstat fields 
Rem     kquinn     01/12/98 -  607968: Correct nowait latch hit ratio calc
Rem     jklein     08/23/96 -  bug 316570 - fix typo
Rem     akolk      08/09/96 -  #387757: fix latch hitratios
Rem     akolk      07/19/96 -  #298462: correcting latch miss rate (Fixing)
Rem     akolk      07/19/96 -  #298462: correcting latch miss rate
Rem     akolk      07/12/96 -  #270507: remove db_block_write_batch
Rem     jloaiza    10/14/95 -  add vtcsh 5.18 (BBN) 2/20/90 Patch level 0
Rem     jloaiza    09/19/95 -  add waitstat
Rem     jloaiza    09/04/95 -  per second stats, split background waits
Rem     drady      09/09/93 -  merge changes from branch 1.1.312.2
Rem     drady      04/26/93 -  Stat name changes for 7.1 
Rem     drady      03/22/93 -  merge changes from branch 1.1.312.1 
Rem     drady      08/24/93 -  bug 173918
Rem     drady      03/04/93 -  fix bug 152986 
Rem     glumpkin   11/23/92 -  Creation 
Rem     glumpkin   11/23/92 -  Renamed from UTLSTATE.SQL 
Rem     glumpkin   10/20/92 -  Renamed from ESTAT.SQL 
Rem     jloaiza    03/26/92 -  add write queue query 
Rem     jloaiza    02/24/92 -  fix latch stats 
Rem     jloaiza    01/17/92 -  improve output 
Rem     jloaiza    01/07/92 -  rework for version 7
Rem   Laursen    01/01/91 - V6 to V7 merge
Rem   Trabosh    09/27/89 - added order by and group by to stats$files
Rem   Loaiza     04/04/89 - fix run dates to do minutes instead of months
Rem   Loaiza     03/31/89 - add kqrst usage column
Rem   Jloaiza    03/16/89 - improve names and formats
Rem   Jloaiza    03/09/89 - make kqrst columns intelligible
Rem   Jloaiza    02/23/89 - changed table names, added dates
Rem   Martin     02/22/89 - Creation
set echo on;
connect internal;

Rem ********************************************************************
Rem                Gather Ending Statistics
Rem ********************************************************************


insert into stats$end_latch select * from v$latch;
insert into stats$end_stats select * from v$sysstat;
insert into stats$end_lib select * from v$librarycache;
update stats$dates set end_time = sysdate;
insert into stats$end_event select * from v$system_event;
insert into stats$end_bck_event 
  select event, sum(total_waits), sum(time_waited)
    from v$session s, v$session_event e
    where type = 'BACKGROUND' and s.sid = e.sid
    group by event;
insert into stats$end_waitstat select * from v$waitstat;
insert into stats$end_roll select * from v$rollstat;
insert into stats$end_file select * from stats$file_view;
insert into stats$end_dc select * from v$rowcache;

Rem ********************************************************************
Rem                Create Summary Tables
Rem ********************************************************************

drop table stats$stats;
drop table stats$latches;
drop table stats$roll;
drop table stats$files;
drop table stats$dc;
drop table stats$lib;
drop table stats$event;
drop table stats$bck_event;
drop table stats$waitstat;

update stats$dates set start_users = (select value 
    from  v$statname n , stats$begin_stats b
       where n.statistic# = b.statistic# and n.name='logons current');
update stats$dates set end_users = (select value 
    from  v$statname n , stats$end_stats b
       where n.statistic# = b.statistic# and n.name='logons current');


create table stats$stats as
select  e.value-b.value change , n.name
   from v$statname n ,  stats$begin_stats b , stats$end_stats e
	where n.statistic# = b.statistic# and n.statistic# = e.statistic#;

create table stats$latches as
select 	e.gets-b.gets gets, 
	e.misses-b.misses misses,
	e.sleeps-b.sleeps sleeps,
	e.immediate_gets-b.immediate_gets immed_gets,
	e.immediate_misses-b.immediate_misses immed_miss,
	n.name
   from v$latchname n ,  stats$begin_latch b , stats$end_latch e
	where n.latch# = b.latch# and n.latch# = e.latch#;

create table stats$event as
  select  e.total_waits-b.total_waits event_count,
          e.time_waited-b.time_waited time_waited,
          e.event
    from  stats$begin_event b , stats$end_event e
    where b.event = e.event
  union all
  select  e.total_waits event_count,
          e.time_waited time_waited,
          e.event	
    from  stats$end_event e
    where e.event not in (select b.event from stats$begin_event b);

Rem background waits
create table stats$bck_event as
  select  e.total_waits-b.total_waits event_count,
          e.time_waited-b.time_waited time_waited,
          e.event
    from  stats$begin_bck_event b , stats$end_bck_event e
    where b.event = e.event
  union all
  select  e.total_waits event_count,
          e.time_waited time_waited,
          e.event	
    from  stats$end_bck_event e
    where e.event not in (select b.event from stats$begin_bck_event b);

Rem subtrace background events out of regular events
update stats$event e 
  set (event_count, time_waited) = 
	(select e.event_count - b.event_count,
	        e.time_waited - b.time_waited
	  from stats$bck_event b
         where e.event = b.event)
   where e.event in (select b.event from stats$bck_event b);

create table stats$waitstat as
select  e.class, 
        e.count - b.count count, 
        e.time - b.time time
  from stats$begin_waitstat b, stats$end_waitstat e
   where e.class = b.class;

create table stats$roll as
select  e.usn undo_segment,
        e.gets-b.gets trans_tbl_gets, 
	e.waits-b.waits trans_tbl_waits, 
	e.writes-b.writes undo_bytes_written,
	e.rssize segment_size_bytes,
        e.xacts-b.xacts xacts,
	e.shrinks-b.shrinks shrinks,
        e.wraps-b.wraps wraps
   from stats$begin_roll b, stats$end_roll e
        where e.usn = b.usn;

create table stats$files as
select b.ts table_space,
       b.name file_name,
       e.pyr-b.pyr phys_reads,
       e.pbr-b.pbr phys_blks_rd,
       e.prt-b.prt phys_rd_time,
       e.pyw-b.pyw phys_writes,
       e.pbw-b.pbw phys_blks_wr,
       e.pwt-b.pwt phys_wrt_tim,
       e.megabytes_size
  from stats$begin_file b, stats$end_file e
       where b.name=e.name;

create table stats$dc as
select b.parameter name,
       e.gets-b.gets get_reqs,
       e.getmisses-b.getmisses get_miss,
       e.scans-b.scans scan_reqs,
       e.scanmisses-b.scanmisses scan_miss,
       e.modifications-b.modifications mod_reqs,
       e.count count,
       e.usage cur_usage
  from stats$begin_dc b, stats$end_dc e
       where b.cache#=e.cache# 
        and  nvl(b.subordinate#,-1) = nvl(e.subordinate#,-1);

create table stats$lib as
select e.namespace,
       e.gets-b.gets gets,
       e.gethits-b.gethits gethits,
       e.pins-b.pins pins,
       e.pinhits-b.pinhits pinhits,
       e.reloads - b.reloads reloads,
       e.invalidations - b.invalidations invalidations
  from stats$begin_lib b, stats$end_lib e
       where b.namespace = e.namespace;


Rem *******************************************************************
Rem              Output statistics
Rem *******************************************************************

spool report.txt;

set charwidth 12
set numwidth 10
Rem Select Library cache statistics.  The pin hit rate should be high.
select namespace library,
       gets, 
       round(decode(gethits,0,1,gethits)/decode(gets,0,1,gets),3) 
          gethitratio,
       pins, 
       round(decode(pinhits,0,1,pinhits)/decode(pins,0,1,pins),3) 
          pinhitratio,
       reloads, invalidations
  from stats$lib;

set charwidth 27;
set numwidth 12;
Rem The total is the total value of the statistic between the time
Rem bstat was run and the time estat was run.  Note that the estat
Rem script logs on as "internal" so the per_logon statistics will
Rem always be based on at least one logon.
select 'Users connected at ',to_char(start_time, 'dd-mon-yy hh24:mi:ss'),':',start_users from stats$dates;
select 'Users connected at ',to_char(end_time, 'dd-mon-yy hh24:mi:ss'),':',end_users from stats$dates;
select 'avg # of connections: ',((start_users+end_users)/2) from stats$dates;

select n1.name "Statistic", 
       n1.change "Total", 
       round(n1.change/trans.change,2) "Per Transaction",
       round(n1.change/((start_users + end_users)/2),2)  "Per Logon",
       round(n1.change/(to_number(to_char(end_time,   'J'))*60*60*24 -
                        to_number(to_char(start_time, 'J'))*60*60*24 +
			to_number(to_char(end_time,   'SSSSS')) -
			to_number(to_char(start_time, 'SSSSS')))
             , 2) "Per Second"
   from 
		stats$stats n1, 
		stats$stats trans, 
		stats$dates
   where 
	 trans.name='user commits'
    and  n1.change != 0
   order by n1.name;


set numwidth 27
Rem Average length of the dirty buffer write queue.  If this is larger 
Rem than the value of:
Rem  1. (db_files * db_file_simultaneous_writes)/2
Rem  or
Rem  2. 1/4 of db_block_buffers
Rem which ever is smaller and also there is a platform specific limit
Rem on the write batch size (normally 1024 or 2048 buffers). If the average 
Rem length of the dirty buffer write queue is larger than the value 
Rem calculated before, increase db_file_simultaneous_writes or db_files.
Rem Also check for disks that are doing many more IOs than other disks.
select queue.change/writes.change "Average Write Queue Length"
  from stats$stats queue, stats$stats writes
 where queue.name  = 'summed dirty queue length'
  and  writes.name = 'write requests';


set charwidth 32;
set numwidth 13;
Rem System wide wait events for non-background processes (PMON, 
Rem SMON, etc).  Times are in hundreths of seconds.  Each one of 
Rem these is a context switch which costs CPU time.  By looking at
Rem the Total Time you can often determine what is the bottleneck 
Rem that processes are waiting for.  This shows the total time spent
Rem waiting for a specific event and the average time per wait on 
Rem that event.
select 	n1.event "Event Name", 
       	n1.event_count "Count",
	n1.time_waited "Total Time",
	round(n1.time_waited/n1.event_count, 2) "Avg Time"
   from stats$event n1
   where n1.event_count > 0
   order by n1.time_waited desc;


Rem System wide wait events for background processes (PMON, SMON, etc)
select 	n1.event "Event Name", 
       	n1.event_count "Count",
	n1.time_waited "Total Time",
	round(n1.time_waited/n1.event_count, 2) "Avg Time"
   from stats$bck_event n1
   where n1.event_count > 0
   order by n1.time_waited desc;


set charwidth 18;
set numwidth 11;
Rem Latch statistics. Latch contention will show up as a large value for
Rem the 'latch free' event in the wait events above.
Rem Sleeps should be low.  The hit_ratio should be high.
select name latch_name, gets, misses,
    round((gets-misses)/decode(gets,0,1,gets),3) 
      hit_ratio,
    sleeps,
    round(sleeps/decode(misses,0,1,misses),3) "SLEEPS/MISS"
   from stats$latches 
    where gets != 0
    order by name;

set numwidth 16
Rem Statistics on no_wait gets of latches.  A no_wait get does not 
Rem wait for the latch to become free, it immediately times out.
select name latch_name,
    immed_gets nowait_gets,
    immed_miss nowait_misses,
    round((immed_gets/(immed_gets+immed_miss)), 3)
      nowait_hit_ratio 
   from stats$latches 
    where immed_gets + immed_miss != 0
    order by name;

Rem Buffer busy wait statistics.  If the value for 'buffer busy wait' in 
Rem the wait event statistics is high, then this table will identify
Rem which class of blocks is having high contention.  If there are high
Rem 'undo header' waits then add more rollback segments.  If there are
Rem high 'segment header' waits then adding freelists might help.  Check
Rem v$session_wait to get the addresses of the actual blocks having
Rem contention.
select * from stats$waitstat 
  where count != 0 
  order by count desc;


set numwidth 19;
Rem Waits_for_trans_tbl high implies you should add rollback segments.
select * from stats$roll;

set charwidth 39
Rem The init.ora parameters currently in effect:
select name, value from v$parameter where isdefault = 'FALSE' 
  order by name;

set charwidth 15;
set numwidth 8;
Rem get_miss and scan_miss should be very low compared to the requests.
Rem cur_usage is the number of entries in the cache that are being used.
select * from stats$dc
 where get_reqs != 0 or scan_reqs != 0 or mod_reqs != 0;


set charwidth 80;
set numwidth 10;
Rem Sum IO operations over tablespaces.
select
  table_space||'                                                 ' 
     table_space,
  sum(phys_reads) reads,  sum(phys_blks_rd) blks_read,
  sum(phys_rd_time) read_time,  sum(phys_writes) writes,
  sum(phys_blks_wr) blks_wrt,  sum(phys_wrt_tim) write_time,
  sum(megabytes_size) megabytes
 from stats$files
 group by table_space
 order by table_space;


set charwidth 48;
set numwidth 10;
Rem I/O should be spread evenly accross drives. A big difference between
Rem phys_reads and phys_blks_rd implies table scans are going on.
select table_space, file_name,
       phys_reads reads, phys_blks_rd blks_read, phys_rd_time read_time,
       phys_writes writes, phys_blks_wr blks_wrt, phys_wrt_tim write_time, 
       megabytes_size megabytes,
       round(decode(phys_blks_rd,0,0,phys_rd_time/phys_blks_rd),2) avg_rt,
       round(decode(phys_reads,0,0,phys_blks_rd/phys_reads),2) "blocks/rd"
 from stats$files order by table_space, file_name;


set charwidth 25
Rem The times that bstat and estat were run.
select to_char(start_time, 'dd-mon-yy hh24:mi:ss') start_time,
       to_char(end_time,   'dd-mon-yy hh24:mi:ss') end_time
  from stats$dates;

set charwidth 75
Rem Versions
select * from v$version;


spool off;

Rem ********************************************************************
Rem                 Drop Temporary Tables
Rem ********************************************************************

drop table stats$dates;

drop table stats$begin_stats;
drop table stats$end_stats;
drop table stats$stats;

drop table stats$begin_latch;
drop table stats$end_latch;
drop table stats$latches;

drop table stats$begin_roll;
drop table stats$end_roll;
drop table stats$roll;

drop table stats$begin_file;
drop table stats$end_file;
drop table stats$files;
drop view stats$file_view;

drop table stats$begin_dc;
drop table stats$end_dc;
drop table stats$dc;

drop table stats$begin_lib;
drop table stats$end_lib;
drop table stats$lib;

drop table stats$begin_event;
drop table stats$end_event;
drop table stats$event;

drop table stats$begin_bck_event;
drop table stats$end_bck_event;
drop table stats$bck_event;

drop table stats$begin_waitstat;
drop table stats$end_waitstat;
drop table stats$waitstat;
