I’m starting this post as an ongoing discussion of research. Today I received a AWR export and wanted to get a feel for what the load is on the system. I imported the AWR report and then wanted a quick overview, so I put together a script to give the AAS over time divided up as CPU, WAIT and IO. Current drawbacks is that the script uses SYSDATE which might not be appropriate if the AWR data is from many days ago. The query seems a bit slow on a month of data, so will be looking at optimizations in the future. + = load demanding CPU o = load waiting for IO to complete – = load waiting for something like a lock, latch or other resource the “8” in the middle of the line is the # of CPU cores. A system that was a 100% maxed out and not waiting for IO or other resources would have pluses (“+”) right up to the number of cores, which is 8 in this case. If the pluses went over the number of cores then there would be contention on CPU resources.
Here is the query for a “live” system:
V$ACTIVE_SESSION_HISTORY + DBA_HIST_ACTIVE_SESS_HISTORY no DBID given
Def v_days=10 -- amount of days to cover in report
Def v_secs=3600 -- size of bucket in seconds, ie one row represents avg over this interval
Def v_bars=5 -- size of one AAS in characters wide
Def v_graph=80 -- width of graph in characters
undef DBID
col graph format a&v_graph
col aas format 999.9
col total format 99999
col npts format 99999
col wait for 999.9
col cpu for 999.9
col io for 999.9
select
to_char(to_date(tday||' '||tmod*&v_secs,'YYMMDD SSSSS'),'DD-MON HH24:MI:SS') tm,
--samples npts,
round(total/&v_secs,1) aas,
round(cpu/&v_secs,1) cpu,
round(io/&v_secs,1) io,
round(waits/&v_secs,1) wait,
-- substr, ie trunc, the whole graph to make sure it doesn't overflow
substr(
-- substr, ie trunc, the graph below the # of CPU cores line
-- draw the whole graph and trunc at # of cores line
substr(
rpad('+',round((cpu*&v_bars)/&v_secs),'+') ||
rpad('o',round((io*&v_bars)/&v_secs),'o') ||
rpad('-',round((waits*&v_bars)/&v_secs),'-') ||
rpad(' ',p.value * &v_bars,' '),0,(p.value * &v_bars)) ||
p.value ||
-- draw the whole graph, then cut off the amount we drew before the # of cores
substr(
rpad('+',round((cpu*&v_bars)/&v_secs),'+') ||
rpad('o',round((io*&v_bars)/&v_secs),'o') ||
rpad('-',round((waits*&v_bars)/&v_secs),'-') ||
rpad(' ',p.value * &v_bars,' '),(p.value * &v_bars),( &v_graph-&v_bars*p.value) )
,0,&v_graph)
graph
from (
select
to_char(sample_time,'YYMMDD') tday
, trunc(to_char(sample_time,'SSSSS')/&v_secs) tmod
, (max(sample_id) - min(sample_id) + 1 ) samples
, sum(decode(session_state,'ON CPU',10,decode(session_type,'BACKGROUND',0,10))) total
, sum(decode(session_state,'ON CPU' ,10,0)) cpu
, sum(decode(session_state,'WAITING',10,0)) -
sum(decode(session_type,'BACKGROUND',decode(session_state,'WAITING',10,0))) -
sum(decode(event,'db file sequential read',10,
'db file scattered read',10,
'db file parallel read',10,
'direct path read',10,
'direct path read temp',10,
'direct path write',10,
'direct path write temp',10, 0)) waits
, sum(decode(session_type,'FOREGROUND',
decode(event,'db file sequential read',10,
'db file scattered read',10,
'db file parallel read',10,
'direct path read',10,
'direct path read temp',10,
'direct path write',10,
'direct path write temp',10, 0))) IO
from
dba_hist_active_sess_history
where sample_time > sysdate - &v_days
and sample_time < (select min(sample_time) from v$active_session_history)
group by trunc(to_char(sample_time,'SSSSS')/&v_secs),
to_char(sample_time,'YYMMDD')
union all
select
to_char(sample_time,'YYMMDD') tday
, trunc(to_char(sample_time,'SSSSS')/&v_secs) tmod
, (max(sample_id) - min(sample_id) + 1 ) samples
, sum(decode(session_state,'ON CPU',1,decode(session_type,'BACKGROUND',0,1))) total
, sum(decode(session_state,'ON CPU' ,1,0)) cpu
, sum(decode(session_state,'WAITING',1,0)) -
sum(decode(session_type,'BACKGROUND',decode(session_state,'WAITING',1,0))) -
sum(decode(event,'db file sequential read',1,
'db file scattered read',1,
'db file parallel read',1,
'direct path read',1,
'direct path read temp',1,
'direct path write',1,
'direct path write temp',1, 0)) waits
, sum(decode(session_type,'FOREGROUND',
decode(event,'db file sequential read',1,
'db file scattered read',1,
'db file parallel read',1,
'direct path read',1,
'direct path read temp',1,
'direct path write',1,
'direct path write temp',1, 0))) IO
from
v$active_session_history
where sample_time > sysdate - &v_days
group by trunc(to_char(sample_time,'SSSSS')/&v_secs),
to_char(sample_time,'YYMMDD')
) ash,
( select value from dba_hist_parameter where parameter_name='cpu_count' and rownum < 2 ) p
order by to_date(tday||' '||tmod*&v_secs,'YYMMDD SSSSS')
/
and output looks like
TM AAS CPU IO WAIT GRAPH
---------------- ------ ------ ------ ------ --------------------------------------------------------------------------------
03-FEB 04:00:00 3.6 1.8 1.8 .1 +++++++++ooooooooo 8
03-FEB 05:00:00 4.1 1.9 2.1 .1 ++++++++++oooooooooo- 8
03-FEB 06:00:00 5.1 2.8 1.9 .3 ++++++++++++++oooooooooo-- 8
03-FEB 07:00:00 5.2 2.6 2.2 .3 +++++++++++++ooooooooooo-- 8
03-FEB 08:00:00 5.9 3.0 2.6 .2 +++++++++++++++ooooooooooooo- 8
03-FEB 09:00:00 6.3 3.2 2.8 .3 ++++++++++++++++oooooooooooooo-- 8
03-FEB 10:00:00 6.3 3.0 2.9 .3 +++++++++++++++ooooooooooooooo-- 8
03-FEB 11:00:00 5.5 2.9 2.5 .2 ++++++++++++++oooooooooooo- 8
03-FEB 12:00:00 5.3 2.6 2.5 .2 +++++++++++++ooooooooooooo- 8
03-FEB 13:00:00 5.4 2.7 2.4 .3 +++++++++++++oooooooooooo- 8
03-FEB 14:00:00 5.5 2.8 2.4 .3 ++++++++++++++oooooooooooo- 8
03-FEB 15:00:00 6.1 2.8 3.1 .2 ++++++++++++++ooooooooooooooo- 8
03-FEB 16:00:00 6.3 3.1 3.0 .2 +++++++++++++++ooooooooooooooo- 8
03-FEB 17:00:00 5.6 2.7 2.6 .2 ++++++++++++++ooooooooooooo- 8
03-FEB 18:00:00 3.4 2.1 1.1 .1 +++++++++++oooooo- 8
03-FEB 19:00:00 4.7 2.5 1.6 .6 +++++++++++++oooooooo--- 8
03-FEB 20:00:00 4.7 2.8 1.8 .1 ++++++++++++++ooooooooo 8
03-FEB 21:00:00 7.3 3.6 3.3 .4 ++++++++++++++++++ooooooooooooooooo-- 8
03-FEB 22:00:00 19.2 6.4 11.5 1.2 ++++++++++++++++++++++++++++++++oooooooo8ooooooooooooooooooooooooooooooooooooooo
03-FEB 23:00:00 12.7 5.2 7.1 .5 ++++++++++++++++++++++++++oooooooooooooo8oooooooooooooooooooooo--
04-FEB 00:00:00 11.1 4.5 6.3 .3 ++++++++++++++++++++++oooooooooooooooooo8oooooooooooooo--
04-FEB 01:00:00 12.8 4.3 5.9 2.6 ++++++++++++++++++++++oooooooooooooooooo8oooooooooooo-------------
04-FEB 02:00:00 4.2 2.5 1.6 .1 ++++++++++++oooooooo 8
04-FEB 03:00:00 2.1 1.3 .7 .1 +++++++ooo 8
04-FEB 04:00:00 2.1 1.3 .9 .0 ++++++oooo 8
04-FEB 05:00:00 2.3 1.2 1.0 .1 ++++++ooooo 8
04-FEB 06:00:00 3.7 2.5 1.0 .2 +++++++++++++ooooo- 8
Here is the query for AWR repository where I’m looking for a particular DBID:
DBA_HIST_ACTIVE_SESS_HISTORY only with particular DBID
Def v_days=10 -- amount of days to cover in report
Def v_secs=3600 -- size of bucket in seconds, ie one row represents avg over this interval
Def v_bars=5 -- size of one AAS in characters wide
Def v_graph=80 -- width of graph in characters
undef DBID
col graph format &v_graph
col aas format 999.9
col total format 99999
col npts format 99999
col wait for 999.9
col cpu for 999.9
col io for 999.9
/* dba_hist_active_sess_history */
select
to_char(to_date(tday||' '||tmod*&v_secs,'YYMMDD SSSSS'),'DD-MON HH24:MI:SS') tm,
--samples npts,
round(total/&v_secs,1) aas,
round(cpu/&v_secs,1) cpu,
round(io/&v_secs,1) io,
round(waits/&v_secs,1) wait,
-- substr, ie trunc, the whole graph to make sure it doesn't overflow
substr(
-- substr, ie trunc, the graph below the # of CPU cores line
-- draw the whole graph and trunc at # of cores line
substr(
rpad('+',round((cpu*&v_bars)/&v_secs),'+') ||
rpad('o',round((io*&v_bars)/&v_secs),'o') ||
rpad('-',round((waits*&v_bars)/&v_secs),'-') ||
rpad(' ',p.value * &v_bars,' '),0,(p.value * &v_bars)) ||
p.value ||
-- draw the whole graph, then cut off the amount we drew before the # of cores
substr(
rpad('+',round((cpu*&v_bars)/&v_secs),'+') ||
rpad('o',round((io*&v_bars)/&v_secs),'o') ||
rpad('-',round((waits*&v_bars)/&v_secs),'-') ||
rpad(' ',p.value * &v_bars,' '),(p.value * &v_bars),( &v_graph-&v_bars*p.value) )
,0,&v_graph)
graph
from (
select
to_char(sample_time,'YYMMDD') tday
, trunc(to_char(sample_time,'SSSSS')/&v_secs) tmod
, (max(sample_id) - min(sample_id) + 1 ) samples
, sum(decode(session_state,'ON CPU',10,decode(session_type,'BACKGROUND',0,10))) total
, sum(decode(session_state,'ON CPU' ,10,0)) cpu
, sum(decode(session_state,'WAITING',10,0)) -
sum(decode(session_type,'BACKGROUND',decode(session_state,'WAITING',10,0))) -
sum(decode(event,'db file sequential read',10,
'db file scattered read',10,
'db file parallel read',10,
'direct path read',10,
'direct path read temp',10,
'direct path write',10,
'direct path write temp',10, 0)) waits
, sum(decode(session_type,'FOREGROUND',
decode(event,'db file sequential read',10,
'db file scattered read',10,
'db file parallel read',10,
'direct path read',10,
'direct path read temp',10,
'direct path write',10,
'direct path write temp',10, 0))) IO
/* for waits I want to subtract out the BACKGROUND
but for CPU I want to count everyone */
from
dba_hist_active_sess_history
where sample_time > sysdate - &v_days
and dbid=&DBID
and sample_time < (select min(sample_time) from v$active_session_history)
group by trunc(to_char(sample_time,'SSSSS')/&v_secs),
to_char(sample_time,'YYMMDD')
) ash,
( select value from dba_hist_parameter where DBID=&DBID and parameter_name='cpu_count' and rownum < 2 ) p
order by to_date(tday||' '||tmod*&v_secs,'YYMMDD SSSSS')
/
Update: here is a sql statement to give the wait/io/cpu graph along with the top two waits: (note, the cpu core count is hard coded at 4 since I didn’t join to dba_hist for the cpu_count parameters. Could be changed in the future version)
DBA_HIST_ACTIVE_SESS_HISTORY with particular DBID, give top wait event names
Def v_secs=3600 -- bucket size
Def v_days=1 -- total time analyze
Def v_bars=5 -- size of one AAS in characters
col aveact format 999.99
col graph format a80
col fpct format 9.99
col spct format 9.99
col tpct format 9.99
col aas1 format 9.99
col aas2 format 9.99
col pct1 format 999
col pct2 format 999
col first format a15
col second format a15
Def p_value=4
--select to_char(start_time,'DD HH:MI:SS'),
select to_char(start_time,'DD HH:MI'),
--samples,
--total,
--waits,
--cpu,
(total/&v_secs) aas,
--round(fpct * (total/&v_secs),2) aas1,
fpct*100 pct1,
decode(fpct,null,null,first) first,
--round(spct * (total/&v_secs),2) aas2,
spct*100 pct2,
decode(spct,null,null,second) second,
-- substr, ie trunc, the whole graph to make sure it doesn't overflow
substr(
-- substr, ie trunc, the graph below the # of CPU cores line
-- draw the whole graph and trunc at # of cores line
substr(
rpad('+',round((cpu*&v_bars)/&v_secs),'+') ||
rpad('o',round((io*&v_bars)/&v_secs),'o') ||
rpad('-',round((waits*&v_bars)/&v_secs),'-') ||
rpad(' ',&p_value * &v_bars,' '),0,(&p_value * &v_bars)) ||
&p_value ||
-- draw the whole graph, then cut off the amount we drew before the # of cores
substr(
rpad('+',round((cpu*&v_bars)/&v_secs),'+') ||
rpad('o',round((io*&v_bars)/&v_secs),'o') ||
rpad('-',round((waits*&v_bars)/&v_secs),'-') ||
rpad(' ',&p_value * &v_bars,' '),(&p_value * &v_bars),( &v_graph-&v_bars*&p_value) )
,0,&v_graph)
graph
-- spct,
-- decode(spct,null,null,second) second,
-- tpct,
-- decode(tpct,null,null,third) third
from (
select start_time
, max(samples) samples
, sum(top.total) total
, round(max(decode(top.seq,1,pct,null)),2) fpct
, substr(max(decode(top.seq,1,decode(top.event,'ON CPU','CPU',event),null)),0,15) first
, round(max(decode(top.seq,2,pct,null)),2) spct
, substr(max(decode(top.seq,2,decode(top.event,'ON CPU','CPU',event),null)),0,15) second
, round(max(decode(top.seq,3,pct,null)),2) tpct
, substr(max(decode(top.seq,3,decode(top.event,'ON CPU','CPU',event),null)),0,10) third
, sum(waits) waits
, sum(io) io
, sum(cpu) cpu
from (
select
to_date(tday||' '||tmod*&v_secs,'YYMMDD SSSSS') start_time
, event
, total
, row_number() over ( partition by id order by total desc ) seq
, ratio_to_report( sum(total)) over ( partition by id ) pct
, max(samples) samples
, sum(decode(event,'ON CPU',total,0)) cpu
, sum(decode(event,'ON CPU',0,
'db file sequential read',0,
'db file scattered read',0,
'db file parallel read',0,
'direct path read',0,
'direct path read temp',0,
'direct path write',0,
'direct path write temp',0, total)) waits
, sum(decode(event,'db file sequential read',total,
'db file scattered read',total,
'db file parallel read',total,
'direct path read',total,
'direct path read temp',total,
'direct path write',total,
'direct path write temp',total, 0)) io
from (
select
to_char(sample_time,'YYMMDD') tday
, trunc(to_char(sample_time,'SSSSS')/&v_secs) tmod
, to_char(sample_time,'YYMMDD')||trunc(to_char(sample_time,'SSSSS')/&v_secs) id
, decode(ash.session_state,'ON CPU','ON CPU',ash.event) event
, sum(decode(session_state,'ON CPU',10,decode(session_type,'BACKGROUND',0,10))) total
, (max(sample_id)-min(sample_id)+1) samples
from
dba_hist_active_sess_history ash
where
-- sample_time > sysdate - &v_days
-- and sample_time < ( select min(sample_time) from v$active_session_history)
dbid=&DBID
group by trunc(to_char(sample_time,'SSSSS')/&v_secs)
, to_char(sample_time,'YYMMDD')
, decode(ash.session_state,'ON CPU','ON CPU',ash.event)
) chunks
group by id, tday, tmod, event, total
) top
group by start_time
) aveact
order by start_time
/
The output looks like
TO_CHAR( AAS PCT1 FIRST PCT2 SECOND GRAPH
-------- ------ ---- --------------- ---- --------------- -------------------------------------
16 05:00 .0 74 CPU 10 log file sync + 4
16 06:00 1.0 67 CPU 11 db file scatter +++++o- 4
16 07:00 1.0 77 CPU 13 db file scatter +++++o 4
16 08:00 1.0 82 CPU 13 db file scatter +++++o 4
16 09:00 1.0 84 CPU 13 db file scatter +++++o 4
16 10:00 1.0 73 CPU 12 db file scatter +++++o- 4
16 11:00 1.0 85 CPU 12 db file scatter ++++++o 4
17 12:00 1.0 87 CPU 11 db file scatter +++++o 4
17 01:00 1.0 81 CPU 16 db file scatter +++++o 4
17 02:00 4.0 94 CPU 5 db file scatter +++++++++++++++++++o4o
17 03:00 3.0 91 CPU 6 db file scatter +++++++++++++++o 4
17 04:00 1.0 79 CPU 16 db file scatter +++++o 4
17 05:00 1.0 83 CPU 15 db file scatter +++++o 4
17 06:00 2.0 83 CPU 13 db file scatter +++++++o 4
17 07:00 2.0 85 CPU 12 db file scatter ++++++o 4
17 08:00 .0 57 CPU 14 db file scatter 4
Comments