Oracle database experiences

Oracle database blog

Category Archives: Database Monitoring

Average Active Sessions – Portable Light Sampling Sessions – Part II

Scope

In the previous post, we have sampled active sessions in the global temporary table PLAN_TABLE. If we want to display the average active sessions like in the part XXI, we will have first to process the data. Nevertheless, in this case we could not use directly the view v$aas_light_sampling_sessions. Instead, we will use a SELECT query based on this view and stored in the PLAN_TABLE table.

aas_light_sampling_sessions

The underlying SELECT of the view v$aas_light_sampling_sessions will be stored in the table PLAN_TABLE. Basically the table lss$_sampling_session will be replaced by the following sub-query:

SELECT lss."SESSION_STATE"                           session_state, 
       lss."WAIT_CLASS#"                             wait_class#,
       TO_DATE(lss."SAMPLE_TIME",'YYYYMMDDHH24MISS') sample_time
FROM plan_table,
     XMLTABLE('/ROW'
     PASSING xmltype(plan_table.other_xml)
     COLUMNS 
         "SESSION_STATE" CHAR(1)      PATH 'SESSION_STATE',
         "WAIT_CLASS#"   NUMBER       PATH 'WAIT_CLASSH',
         "SAMPLE_TIME"   VARCHAR2(16) PATH 'SAMPLE_TIME') 
     lss
WHERE id > 0
  AND id IS NOT NULL;

The XML data field values are available as column values with the XMLTABLE function. You will find below a SQL script to store the SELECT statement linked to aas_light_sampling_sessions:

-- =======================================================================
--  File Name     : aas_light_sampling_sessions.sql
--  Area          :
--  Description   : Portable Light Sampling Sessions
--  Author        : Arnaud Fargues
--  Tested On     : 12.1, 11.2
--  Plateform     : 
--  Requires      : 
--  Creation Date : 14.05.2016
--  Modified      : 31.07.2016  
-- =======================================================================

INSERT INTO plan_table(object_name,other_xml)
VALUES ('aas_light_sampling_sessions',TO_CLOB('
SELECT sample_yyyymmddhhmi,
SUBSTR(sample_yyyymmddhhmi,9,2) || '':'' || SUBSTR(sample_yyyymmddhhmi,11,2) BEGIN_TIME,
aas1 C_CPU,
aas1+aas2 C_OTHER,
aas1+aas2+aas3 C_APPLICATION,
aas1+aas2+aas3+aas4 C_CONFIGURATION,
aas1+aas2+aas3+aas4+aas5 C_ADMINISTRATIVE,
aas1+aas2+aas3+aas4+aas5+aas6 C_CONCURRENCY,
aas1+aas2+aas3+aas4+aas5+aas6+aas7 C_COMMIT,
aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8 C_NETWORK,
aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9 C_USER_IO,
aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10 C_SYSTEM_IO,
aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11 C_SCHEDULER,
aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12 C_CLUSTER,
aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12+aas13 C_QUEUEING,
MAX(CEIL(aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12+aas13)) OVER() MAX_AAS
FROM (SELECT sample_yyyymmddhhmi,
TRUNC((ccpu/(nb_samples)),3) aas1,
TRUNC((cother/(nb_samples)),3) aas2,
TRUNC((capplication/(nb_samples)),3) aas3,
TRUNC((cconfiguration/(nb_samples)),3) aas4,
TRUNC((cadministrative/(nb_samples)),3) aas5,
TRUNC((cconcurrency/(nb_samples)),3) aas6,
TRUNC((ccommit/(nb_samples)),3) aas7,
TRUNC((cnetwork/(nb_samples)),3) aas8,
TRUNC((cuser_io/(nb_samples)),3) aas9,
TRUNC((csystem_io/(nb_samples)),3) aas10, 
TRUNC((cscheduler/(nb_samples)),3) aas11, 
TRUNC((ccluster/(nb_samples)),3) aas12, 
TRUNC((cqueueing/(nb_samples)),3)aas13
FROM (SELECT NVL(co_base_qry.sample_yyyymmddhhmi,time_window.start_time) sample_yyyymmddhhmi,
NVL(co_base_qry.nb_samples,1) nb_samples,
NVL(co_base_qry.ccpu,0) ccpu,
NVL(co_base_qry.cother,0) cother,
NVL(co_base_qry.capplication,0) capplication,
NVL(co_base_qry.cconfiguration,0) cconfiguration,
NVL(co_base_qry.cadministrative,0) cadministrative,
NVL(co_base_qry.cconcurrency,0) cconcurrency,
NVL(co_base_qry.ccommit,0) ccommit,
NVL(co_base_qry.cnetwork,0) cnetwork,
NVL(co_base_qry.cuser_io,0) cuser_io,
NVL(co_base_qry.csystem_io,0) csystem_io,
NVL(co_base_qry.cscheduler,0) cscheduler,
NVL(co_base_qry.ccluster,0) ccluster,
NVL(co_base_qry.cqueueing,0)cqueueing
FROM (SELECT TO_CHAR(SYSDATE - (LEVEL/24/60),''YYYYMMDDHH24MI'') start_time
FROM DUAL 
CONNECT BY LEVEL <= 61
) time_window
LEFT OUTER JOIN 
(SELECT TO_CHAR(sample_time,''YYYYMMDDHH24MI'') sample_yyyymmddhhmi,
30 nb_samples,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),-1,1)) ccpu,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),0,1)) cother,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),1,1)) capplication,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),2,1)) cconfiguration,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),3,1)) cadministrative,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),4,1)) cconcurrency,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),5,1)) ccommit,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),7,1)) cnetwork,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),8,1)) cuser_io,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),9,1)) csystem_io,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),10,1)) cscheduler,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),11,1)) ccluster,
COUNT(DECODE(DECODE(session_state,''C'',-1,wait_class#),12,1)) cqueueing
FROM (
SELECT lss."SESSION_STATE" session_state, 
lss."WAIT_CLASS#" wait_class#,
TO_DATE(lss."SAMPLE_TIME",''YYYYMMDDHH24MISS'') sample_time
FROM plan_table,
XMLTABLE(''/ROW''
PASSING xmltype(plan_table.other_xml)
COLUMNS 
"SESSION_STATE" CHAR(1) PATH ''SESSION_STATE'',
"WAIT_CLASS#" NUMBER PATH ''WAIT_CLASSH'',
"SAMPLE_TIME" VARCHAR2(16) PATH ''SAMPLE_TIME'') 
lss
WHERE id > 0
AND id IS NOT NULL)
GROUP BY TO_CHAR(sample_time,''YYYYMMDDHH24MI'')
) co_base_qry
ON time_window.start_time=co_base_qry.sample_yyyymmddhhmi
)
) ORDER BY sample_yyyymmddhhmi'));

COMMIT;

As you can see, the query has less than 4000 characters. It is due to the fact that we are using the function DBMS_XMLGEN.GETXMLTYPE in a way that can handle only queries with less than 4000 characters.

Modified SVG source query

We will use the query defined in the part XXI as a starting point. We will modify the source query as follow:

SELECT XMLTRANSFORM
   (DBMS_XMLGEN.GETXMLTYPE(other_xml)
    ...
FROM plan_table
WHERE object_name='aas_light_sampling_sessions';

XSLT variables

  • The variable “graph_name” is set to ‘PLSS Active Sessions – Waiting + Working’,
  • The variable “cpu_count” is set to ‘4’.

Modified query

SET LINESIZE      2000
SET LONGCHUNKSIZE 30000
SET LONG          30000

SET FEEDBACK OFF
SET VERIFY   OFF
SET PAGESIZE 0

SET HEADING OFF

SPOOL generate_svg_plss.svg

SELECT XMLTRANSFORM
   (DBMS_XMLGEN.GETXMLTYPE(other_xml)
,      XMLTYPE.CREATEXML
   (TO_CLOB(
    '<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     <xsl:variable name="margin_top">20</xsl:variable>
     <xsl:variable name="margin_bottom">30</xsl:variable>
     <xsl:variable name="margin_left">40</xsl:variable>
     <xsl:variable name="margin_right">100</xsl:variable>
     <xsl:variable name="bar_width">10</xsl:variable>
     <xsl:variable name="graph_width"><xsl:value-of select="600+$margin_left+$margin_right"/></xsl:variable>
     <xsl:variable name="graph_height"><xsl:value-of select="100+$margin_top+$margin_bottom"/></xsl:variable>
     <xsl:variable name="graph_name">PLSS Active Sessions - Waiting + Working</xsl:variable>
     <xsl:variable name="graph_unit">Session Count</xsl:variable>
     <xsl:variable name="yval_max"><xsl:value-of select="/descendant::MAX_AAS[position()=1]"/></xsl:variable>
     <xsl:variable name="yval_min">0</xsl:variable>
     <xsl:variable name="cpu_count"><xsl:value-of select="4"/></xsl:variable>
       <xsl:template match="/">'
           )
    || 
    TO_CLOB(
         '<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" width="{$graph_width}" height="{$graph_height}">
           <text x="{$margin_left+1}" y="{($margin_top)-5}" style="fill: #000000; stroke: none;font-size:10px;text-anchor=start"><xsl:value-of select="$graph_name"/></text>
           <text x="{($margin_bottom)-($graph_height)}" y="10" transform="rotate(-90)" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$graph_unit"/></text>
           <line x1="{($margin_left)-5}" y1="{($graph_height)-($margin_bottom)-0}"   x2="{($graph_width)-($margin_right)+5}" y2="{($graph_height)-($margin_bottom)-0}"  style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($graph_height)-($margin_bottom)-25}"  x2="{($graph_width)-($margin_right)+5}" y2="{($graph_height)-($margin_bottom)-25}" style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($graph_height)-($margin_bottom)-50}"  x2="{($graph_width)-($margin_right)+5}" y2="{($graph_height)-($margin_bottom)-50}" style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($graph_height)-($margin_bottom)-75}"  x2="{($graph_width)-($margin_right)+5}" y2="{($graph_height)-($margin_bottom)-75}" style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($graph_height)-($margin_bottom)-100}" x2="{($graph_width)-($margin_right)+5}" y2="{($graph_height)-($margin_bottom)-100}" style="stroke:lightblue;stroke-width:1" />
           <text x="{($margin_left)-24}" y="{($graph_height)-($margin_bottom)-2}"   style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="format-number(($yval_min),''00.00'')"/></text>
           <text x="{($margin_left)-24}" y="{($graph_height)-($margin_bottom)-25}"  style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="format-number((($yval_min)+(1*(($yval_max)-($yval_min)) div 4)),''00.00'')"/></text>
           <text x="{($margin_left)-24}" y="{($graph_height)-($margin_bottom)-50}"  style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="format-number((($yval_min)+((($yval_max)-($yval_min)) div 2)),''00.00'')"/></text>
           <text x="{($margin_left)-24}" y="{($graph_height)-($margin_bottom)-75}"  style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="format-number((($yval_min)+(3*(($yval_max)-($yval_min)) div 4)),''00.00'')"/></text>
           <text x="{($margin_left)-24}" y="{($graph_height)-($margin_bottom)-100}" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="format-number(($yval_max),''00.00'')"/></text>
           <line x1="{$margin_left}" y1="{($graph_height)-($margin_bottom)}" x2="{$margin_left}" y2="{($graph_height)-($margin_bottom)-100}" style="stroke:lightblue;stroke-width:1" />'
           )
    || 
    TO_CLOB(
          '<xsl:for-each select="ROWSET/ROW/BEGIN_TIME">
             <xsl:choose>
               <xsl:when test="(position()-1) mod 5=0">
                 <text x="{($margin_left)-9+($bar_width*(position()-1))}" y="{($graph_height)-($margin_bottom)+12}" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="self::node()"/></text>
                 <line x1="{($margin_left)+($bar_width*(position()-1))}" y1="{($graph_height)-($margin_bottom)+4}" x2="{($margin_left)+($bar_width*(position()-1))}" y2="{($graph_height)-($margin_bottom)-100}" style="stroke:lightblue;stroke-width:1" /> 
               </xsl:when>
               <xsl:otherwise>
                 <line x1="{($margin_left)+($bar_width*(position()-1))}" y1="{($graph_height)-($margin_bottom)+3}" x2="{($margin_left)+($bar_width*(position()-1))}" y2="{($graph_height)-($margin_bottom)+0}" style="stroke:lightblue;stroke-width:1" /> 
               </xsl:otherwise>
             </xsl:choose>    
           </xsl:for-each>
           <xsl:variable name="v_path0">
             <xsl:for-each select="ROWSET/ROW/C_CPU">
               <xsl:variable name="x_val0">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val0">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val0,'','',$y_val0,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path0} {$x_val0},{($graph_height)-($margin_bottom)} {$margin_left},{($graph_height)-($margin_bottom)}" style="fill:limegreen;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path1">
             <xsl:for-each select="ROWSET/ROW/C_OTHER">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val1">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val1">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val1,'','',$y_val1,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path0}{$v_path1}" style="fill:hotpink;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path2">
             <xsl:for-each select="ROWSET/ROW/C_APPLICATION">
               <xsl:variable name="x_val2">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val2">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val2,'','',$y_val2,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path1}{$v_path2}" style="fill:indianred;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path3">
             <xsl:for-each select="ROWSET/ROW/C_CONFIGURATION">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val3">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val3">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val3,'','',$y_val3,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path2}{$v_path3}" style="fill:olive;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path4">
             <xsl:for-each select="ROWSET/ROW/C_ADMINISTRATIVE">
               <xsl:variable name="x_val4">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val4">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val4,'','',$y_val4,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path3}{$v_path4}" style="fill:gray;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path5">
             <xsl:for-each select="ROWSET/ROW/C_CONCURRENCY">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val5">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val5">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val5,'','',$y_val5,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path4}{$v_path5}" style="fill:sienna;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path6">
             <xsl:for-each select="ROWSET/ROW/C_COMMIT">
               <xsl:variable name="x_val6">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val6">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val6,'','',$y_val6,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path5}{$v_path6}" style="fill:orange;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path7">
             <xsl:for-each select="ROWSET/ROW/C_NETWORK">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val7">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val7">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val7,'','',$y_val7,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path6}{$v_path7}" style="fill:tan;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path8">
             <xsl:for-each select="ROWSET/ROW/C_USER_IO">
               <xsl:variable name="x_val8">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val8">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val8,'','',$y_val8,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path7}{$v_path8}" style="fill:royalblue;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path9">
             <xsl:for-each select="ROWSET/ROW/C_SYSTEM_IO">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val9">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val9">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val9,'','',$y_val9,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path8}{$v_path9}" style="fill:skyblue;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path10">
             <xsl:for-each select="ROWSET/ROW/C_SCHEDULER">
               <xsl:variable name="x_val10">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val10">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val10,'','',$y_val10,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path9}{$v_path10}" style="fill:lightcyan;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path11">
             <xsl:for-each select="ROWSET/ROW/C_CLUSTER">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val11">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val11">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val11,'','',$y_val11,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path10}{$v_path11}" style="fill:lightgray;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path12">
             <xsl:for-each select="ROWSET/ROW/C_QUEUEING">
               <xsl:variable name="x_val12">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val12">
                 <xsl:value-of select="round(($graph_height)-($margin_bottom)-((($yval_min)-(self::node()))*(100 div (($yval_min)-($yval_max)))))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val12,'','',$y_val12,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path11}{$v_path12}" style="fill:bisque;stroke:none;stroke-width:1" />
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+5}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">CPU</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+0}" width="{10}" height="{6}" fill="limegreen" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+13}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Other</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+8}" width="{10}" height="{6}" fill="hotpink" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+21}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Application</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+16}" width="{10}" height="{6}" fill="indianred" stroke="black"/>   
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+29}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Configuration</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+24}" width="{10}" height="{6}" fill="olive" stroke="black"/>   
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+37}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Administrative</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+32}" width="{10}" height="{6}" fill="gray" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+45}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Concurrency</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+40}" width="{10}" height="{6}" fill="sienna" stroke="black"/>'
           ) 
    || 
    TO_CLOB(
          '<text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+53}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Commit</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+48}" width="{10}" height="{6}" fill="orange" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+61}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Network</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+56}" width="{10}" height="{6}" fill="tan" stroke="black"/>  
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+69}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">User IO</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+64}" width="{10}" height="{6}" fill="royalblue" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+77}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">System IO</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+72}" width="{10}" height="{6}" fill="skyblue" stroke="black"/>
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+85}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Scheduler</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+80}" width="{10}" height="{6}" fill="lightcyan" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+93}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Cluster</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+88}" width="{10}" height="{6}" fill="lightgray" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+101}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Queueing</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+96}" width="{10}" height="{6}" fill="bisque" stroke="black"/> 
           <xsl:choose>
             <xsl:when test="$yval_max&gt;$cpu_count">
               <line x1="{($margin_left)-5}" y1="{($graph_height)-($margin_bottom)-((($yval_min)-($cpu_count))*(100 div (($yval_min)-($yval_max))))}" x2="{($graph_width)-($margin_right)+5}" y2="{($graph_height)-($margin_bottom)-((($yval_min)-($cpu_count))*(100 div (($yval_min)-($yval_max))))}" style="stroke-dasharray: 9, 5;stroke:red;stroke-width:1" />
               <text x="{($margin_left)+2}" y="{($graph_height)-($margin_bottom)-((($yval_min)-($cpu_count))*(100 div (($yval_min)-($yval_max))))-2}" style="fill:red; stroke: none;font-size:8px;text-anchor=start">CPU cores</text>
             </xsl:when>
             <xsl:otherwise>
               <text x="{($margin_left)-38}" y="{($graph_height)-($margin_bottom)-93}" style="fill:red; stroke: none;font-size:6px;text-anchor=start"><xsl:value-of select="format-number((($yval_max) div ($cpu_count))*100,''00'')"/>% cpu cores</text>
             </xsl:otherwise>
           </xsl:choose>   
         </svg>
       </xsl:template>
     </xsl:stylesheet>'
           )
   )
   ) 
FROM plan_table
WHERE object_name='aas_light_sampling_sessions';

SPOOL OFF
SET HEADING ON

SET VERIFY   ON
SET FEEDBACK ON

This query will be saved in the file generate_svg_plss.sql.

Sampling + SVG generation

In order to display the average active sessions of the PDB1 container database we will:

  1. Connect to the PDB1 container database as the PLSS user,
  2. Execute the previous script aas_light_sampling_sessions.sql in order to store the aas_light_sampling_sessions query,
  3. Execute the script plss_sampling.sql in order to sample the active sessions every 2 seconds on a one minute period,
  4. Execute the script generate_svg_plss.sql in order to generate a SVG graph,
  5. Repeat the steps 3 and 4 as many times as you want.

You will find below an example of such a script:

-- =======================================================================
--  File Name     : plss_master.sql
--  Area          :
--  Description   : Portable Light Sampling Sessions
--  Author        : Arnaud Fargues
--  Tested On     : 12.1, 11.2
--  Plateform     : 
--  Requires      : 
--  Creation Date : 31.07.2016
--  Modified      :   
-- =======================================================================

SET DEFINE OFF

--
--Load aas_light_sampling_sessions query into PLAN_TABLE
--
@aas_light_sampling_sessions.sql

--
--1
--
@plss_sampling.sql

@generate_svg_plss.sql

--
--2
--
@plss_sampling.sql

@generate_svg_plss.sql

--
--3
--
@plss_sampling.sql

@generate_svg_plss.sql

--
--4
--
@plss_sampling.sql

@generate_svg_plss.sql

--
--5
--
@plss_sampling.sql

@generate_svg_plss.sql

--
--6
--
@plss_sampling.sql

@generate_svg_plss.sql

--
--7
--
@plss_sampling.sql

@generate_svg_plss.sql

--
--8
--
@plss_sampling.sql

@generate_svg_plss.sql

--
--9
--
@plss_sampling.sql

@generate_svg_plss.sql

--
--10
--
@plss_sampling.sql

@generate_svg_plss.sql

Result:

generate_svg_plss

Remark:

  • You could repeat the steps @plss_sampling.sql and @generate_svg_plss.sql a high number of times and if you want to display the average active sessions every 5 minutes for example, you could copy the file generate_svg_plss.svg every 5 minutes to check this activity.

Average Active Sessions – Portable Light Sampling Sessions – Part I

Scope

In some situations, it might happened that you have access to an Oracle database but you can not set up a Light Sampling Sessions installation because you have limited privileges e.g. you don’t have the CREATE TABLE system privilege.
However with some limited privileges you could display a graph on the Average Active Sessions.
In the rest of this post we will make the assumption that an Oracle user has been created in a 12.1 PDB database.

User creation

Let’s create a user PLSS in the PDB1 container:

@> connect / as sysdba
Connected.
SYS@orcl> ALTER SESSION SET CONTAINER=PDB1;

Session altered.

SYS@orcl> show con_name;

CON_NAME
------------------------------
PDB1
SYS@orcl> CREATE USER PLSS IDENTIFIED BY plss
  2  CONTAINER=CURRENT;

User created.

This user will have only the CREATE SESSION privilege and will have access to the V$SESSION view:

User privileges

SYS@orcl> GRANT CREATE SESSION TO PLSS;

Grant succeeded.

SYS@orcl> GRANT SELECT ON SYS.V_$SESSION TO PLSS;

Grant succeeded.

Plss sampling

As you can see the Oracle user PLSS has limited privileges. How can he store data in the database?
We could use the global temporary table PLAN_TABLE. The data could be stored in this table during the session lifetime.

Basically, we will use an anonymous block similar to the procedure DBMS_SAMPLING_SESSION.start_sampling to record active sessions as following:

-- =======================================================================
--  File Name     : plss_sampling.sql
--  Area          :
--  Description   : Portable Light Sampling Sessions
--  Author        : Arnaud Fargues
--  Tested On     : 12.1, 11.2
--  Plateform     : 
--  Requires      : 
--  Creation Date : 12.05.2016
--  Modified      :   
-- =======================================================================

DECLARE
   v_nb_sample      INTEGER;
   v_index          INTEGER;
   v_cur_date       DATE;
   v_sample_id      NUMBER;
   v_sample_per_min NUMBER;
   v_session_sid    NUMBER;
   v_start_date     DATE;

   v_sampling_interval_sec NUMBER := 2;
   v_sampling_window_min   NUMBER := 1;

BEGIN

   v_sample_per_min := 60 / v_sampling_interval_sec;
   v_nb_sample      := v_sampling_window_min * v_sample_per_min;

   SELECT NVL(MAX(id),0)
   INTO v_sample_id
   FROM plan_table;

   SELECT SYS_CONTEXT ('USERENV', 'SID')
   INTO v_session_sid
   FROM DUAL;

   FOR v_index IN 1..v_nb_sample
   LOOP
      v_sample_id := v_sample_id + 1;

      v_cur_date := SYSDATE;

      INSERT INTO plan_table (id,other_xml)
      SELECT v_sample_id,
             XMLSERIALIZE(CONTENT
         (XMLELEMENT("ROW",
             XMLELEMENT("SAMPLE_ID",v_sample_id ),
             XMLELEMENT("SAMPLE_TIME",TO_CHAR(v_cur_date,'YYYYMMDDHH24MISS')),
             XMLELEMENT("SID",SID),
             XMLELEMENT("SERIALH",SERIAL#),
             XMLELEMENT("SESSION_STATE",decode(state,'WAITING','W','C')),
             XMLELEMENT("USERH",user#),
             XMLELEMENT("TYPE",type),
             XMLELEMENT("COMMAND",command),
             XMLELEMENT("PROGRAM",program),
             XMLELEMENT("MODULE",module),
             XMLELEMENT("ACTION",action),
             XMLELEMENT("SERVICE_NAME",service_name),
             XMLELEMENT("CLIENT_IDENTIFIER",client_identifier),
             XMLELEMENT("EVENTH",event#),
             XMLELEMENT("EVENT",event),
             XMLELEMENT("SEQH",seq#),
             XMLELEMENT("P1",p1),
             XMLELEMENT("P2",p2),
             XMLELEMENT("P3",p3),
             XMLELEMENT("WAIT_CLASSH",wait_class#),
             XMLELEMENT("WAIT_TIME_MICRO",wait_time_micro),
             XMLELEMENT("SQL_ID",sql_id),
             XMLELEMENT("SQL_HASH_VALUE",sql_hash_value),
             XMLELEMENT("SQL_CHILD_NUMBER",sql_child_number) )))
      FROM v$session
      WHERE status='ACTIVE'
        AND ((state = 'WAITING' AND wait_class# <> 6)
              OR (state <> 'WAITING' AND sid <> v_session_sid));

      v_start_date := SYSDATE;
      
      WHILE SYSDATE <= v_start_date + (v_sampling_interval_sec/86400) 
      LOOP
         NULL;
      END LOOP;

   END LOOP;
END ;
/

Remarks:

  • Every sample will be stored in the column other_xml of PLAN_TABLE as XML data,
  • The sample_id values will be also stored in the column id of PLAN_TABLE,
  • The function XMLSERIALIZE is used to convert XML datatype into CLOB datatype,
  • We have used the function XMLELEMENT instead of XMLFOREST in order to store explicitly NULL values,
  • The symbol # contained in some column names has been replaced by H because such a symbol is invalid in a XML tag name,
  • We have replaced the DBMS_LOCK.SLEEP procedure with a WHILE LOOP,
  • We will record the active sessions every 2 seconds during 1 minute.

Shortly

We will see how to generate a SVG graph with those “temporary data”.

Average Active Sessions – Light Sampling Sessions – Database Group – RAC Update

Scope

Back to part XXII, it could be interesting to have a consolidated activity view of non-CDB databases or of PDB pluggable databases belonging to different CDBs.
We will define the concept of “database group”, in which one database will be the primary database (like the CDB$ROOT container database) and the other databases will be defined as secondary databases.

We will take two databases as an example. In our case we will use a CDB database where the CDB$ROOT container will be the primary database and the PDB1 container will be the secondary database. We will also modify the structure of the table lss$_sampling_session in order to handle RAC instances.

Let’s begin with the PDB1 container.

PDB1 – Tablespace modification

We will use the ‘LSS_REPOSITORY’ tablespace that was already created in the post “Average Active Sessions and CDB – Light Sampling Sessions”, but we will increase its size to 150 Mo:

@> connect / as sysdba
Connected.
SYS@orcl> ALTER SESSION SET CONTAINER=PDB1;

Session altered.

SYS@orcl> show con_name;

CON_NAME
------------------------------
PDB1
SYS@orcl> ALTER DATABASE
  2  DATAFILE 'C:\APP\ORACLE\ORADATA\ORCL\PDB1\LSS_REPOSITORY01.DBF' RESIZE 150 M;

Database altered.

PDB1 – Local user creation

Connected to the PDB1 container, we will create the LSS local user:

SYS@orcl> CREATE USER LSS IDENTIFIED BY lss
  2  CONTAINER=CURRENT
  3  DEFAULT TABLESPACE LSS_REPOSITORY
  4  QUOTA UNLIMITED ON LSS_REPOSITORY;

User created.

PDB1 – Base privileges

We will grant the following privileges to the LSS user:

SYS@orcl> GRANT CREATE SESSION      TO LSS;

Grant succeeded.

SYS@orcl> GRANT SELECT_CATALOG_ROLE TO LSS;

Grant succeeded.

SYS@orcl> GRANT CREATE PROCEDURE    TO LSS;

Grant succeeded.

SYS@orcl> GRANT CREATE VIEW         TO LSS;

Grant succeeded.

SYS@orcl> GRANT CREATE TABLE        TO LSS;

Grant succeeded.

PDB1 – Table creation

Let’s now create the table lss$_sampling_session in the LSS schema:

@> connect lss@pdb1
Enter password:
Connected.
LSS@pdb1> show con_name;

CON_NAME
------------------------------
PDB1
LSS@pdb1> CREATE TABLE lss$_sampling_session
  2  AS
  3  SELECT CAST (1 AS NUMBER) sample_id,
  4         CAST (NULL AS DATE) sample_time,
  5         sid,
  6         serial#,
  7         user#,
  8         type,
  9         command,
 10         program,
 11         module,
 12         action,
 13         service_name,
 14         client_identifier,
 15         CAST ('1' AS CHAR(1)) session_state,
 16         state,
 17         event#,
 18         event,
 19         seq#,
 20         p1,
 21         p2,
 22         p3,
 23         wait_class#,
 24         wait_time_micro,
 25         sql_id,
 26         con_id,
 27         inst_id,
 28         sql_hash_value,
 29         sql_child_number,
 30         CAST (1 AS NUMBER) element_id
 31  FROM gv$session
 32  WHERE 1=2;

Table created.

We have added four new columns:

  • inst_id: to handle RAC instances,
  • sql_hash_value and sql_child_number: to handle more precisely sql statements,
  • element_id: to handle the database group. This number must be unique in all the databases that belong to a database group.

PDB1 – Other privileges

Let’s grant the SELECT privilege on the underlying object of gv$session in order to use it in a procedure:

@> connect / as sysdba
Connected.
SYS@orcl> ALTER SESSION SET CONTAINER=PDB1;

Session altered.

SYS@orcl> show con_name;

CON_NAME
------------------------------
PDB1
SYS@orcl> GRANT SELECT ON SYS.GV_$SESSION TO LSS;

Grant succeeded.

Let’s grant the EXECUTE privilege on the DBMS_LOCK package:

SYS@orcl> GRANT EXECUTE ON DBMS_LOCK TO LSS;

Grant succeeded.

PDB1 – Package specifications

Let’s create the package specifications as following:

CREATE OR REPLACE PACKAGE LSS.DBMS_SAMPLING_SESSION AS 

-- =======================================================================
--  Package       : DBMS_SAMPLING_SESSION
--  Description   : Sample active sessions
--  Author        : Arnaud Fargues
--  Creation      : 14.06.2015
--  Modifications : 
-- =======================================================================

   PROCEDURE start_sampling (
      p_sampling_window_min   IN NUMBER DEFAULT 60,
      p_sampling_interval_sec IN NUMBER DEFAULT 5);

END DBMS_SAMPLING_SESSION;
/

PDB1 – Package body

You will find below the package body:

CREATE OR REPLACE PACKAGE BODY LSS.DBMS_SAMPLING_SESSION AS

PROCEDURE start_sampling (
   p_sampling_window_min   IN NUMBER DEFAULT 60,
   p_sampling_interval_sec IN NUMBER DEFAULT 5)

-- =======================================================================
--  Procedure     : start_sampling
--  Description   : Starts sampling active sessions
--  Parameters    : p_sampling_window_min   : sampling period time in minutes
--                  p_sampling_interval_sec : sampling period interval in seconds
--  Author        : Arnaud Fargues
--  Creation      : 14.06.2015
--  Modifications : 10.12.2015 Handle RAC instances
--                  12.01.2016 Add columns sql_hash_value and sql_child_number
--                  22.01.2016 Add column element_id
-- =======================================================================

AS
   v_nb_sample      INTEGER;
   v_index          INTEGER;
   v_cur_date       DATE;
   v_sample_id      NUMBER;
   v_sample_per_min NUMBER;
   v_session_sid    NUMBER;
BEGIN

   v_sample_per_min := 60 / p_sampling_interval_sec;
   v_nb_sample      := p_sampling_window_min * v_sample_per_min;
   
   SELECT NVL(MAX(sample_id),0)
   INTO v_sample_id
   FROM lss$_sampling_session;

   SELECT SYS_CONTEXT ('USERENV', 'SID')
   INTO v_session_sid
   FROM DUAL;

   FOR v_index IN 1..v_nb_sample
   LOOP
      v_sample_id := v_sample_id + 1;

      DBMS_APPLICATION_INFO.SET_MODULE(
         module_name => 'DBMS_SAMPLING_SESSION',
         action_name => 'Sample:'|| TO_CHAR(v_sample_id));

      v_cur_date := SYSDATE;

      INSERT INTO lss$_sampling_session(
         sample_id,
         sample_time,
         inst_id,
         sid,
         serial#,
         session_state,
         state,
         user#,
         type,
         command,
         program,
         module,
         action,
         service_name,
         client_identifier,
         event#,
         event,
         seq#,
         p1,
         p2,
         p3,
         wait_class#,
         wait_time_micro,
         sql_id,
         sql_hash_value,
         sql_child_number,
         con_id,
         element_id)
      SELECT
         v_sample_id,
         v_cur_date,
         inst_id,
         sid,
         serial#,
         decode(state,'WAITING','W','C'),
         state,
         user#,
         type,
         command,
         program,
         module,
         action,
         service_name,
         client_identifier,
         event#,
         event,
         seq#,
         p1,
         p2,
         p3,
         wait_class#,
         wait_time_micro,
         sql_id,
         sql_hash_value,
         sql_child_number,
         con_id,
         2
      FROM gv$session
      WHERE status='ACTIVE'
        AND ((state = 'WAITING' AND wait_class# <> 6)
              OR (state <> 'WAITING' AND ((SID = v_session_sid AND event# <> 389) OR sid <> v_session_sid)));

      IF v_index MOD v_sample_per_min = 0 THEN
         COMMIT;
      END IF;

      DBMS_LOCK.SLEEP(p_sampling_interval_sec);

   END LOOP;
END start_sampling;

END DBMS_SAMPLING_SESSION;
/

Remarks:

  • For the PDB1 container which is a secondary database the element_id value is 2,
  • For non-CDB databases, you can set the con_id column value to 0.

Let’s continue with the CDB$ROOT container.

CDB$ROOT – Table update

We will add the four new columns to the table lss$_sampling_session in the C##LSS schema:

@> connect c##lss@orcl
Enter password:
Connected.
C##LSS@orcl> show con_name;

CON_NAME
------------------------------
CDB$ROOT
C##LSS@orcl> ALTER TABLE lss$_sampling_session
  2  ADD (inst_id           NUMBER,
  3       sql_hash_value    NUMBER,
  4       sql_child_number  NUMBER,
  5       element_id        NUMBER);

Table altered.

CDB$ROOT – Other privileges

Let’s grant the SELECT privilege on the underlying object of gv$session in order to use it in a procedure instead of v$session:

@> connect / as sysdba
Connected.
SYS@orcl> show con_name

CON_NAME
------------------------------
CDB$ROOT
SYS@orcl> GRANT SELECT ON SYS.GV_$SESSION TO C##LSS;

Grant succeeded.

Gv$session is a view that contains data linked to several containers (CDB$ROOT, PDB’s). Because the common user C##LSS should see data of all those containers we will set the CONTAINER_DATA attribute as follow:

SYS@orcl> ALTER USER C##LSS
  2  SET CONTAINER_DATA = (CDB$ROOT,PDB1)
  3  FOR gv_$session CONTAINER=CURRENT;

User altered.

CDB$ROOT – Package body

The package body is the same than for the PDB1 container except that the value of element_id is 1 for CDB$ROOT:

You must replace this code fragment

...         con_id,
         2
      FROM gv$session
      WHERE status='ACTIVE'...

by

...         con_id,
         1
      FROM gv$session
      WHERE status='ACTIVE'...

Shortly

We will consolidated the two database activities in a stacked area graph and compare it to the graph described in the part XXII.

Average Active Sessions – Light Sampling Sessions – Views update

Scope

The views v$aas_light_sampling_sessions, v$cdb_pdb_aas_lss, v$top_activity_session_lss and v$session_activity_lss defined in the Part XXI, Part XXII, Part XXIII and Part XXIV respectively, are better suited for high database activity periods e.g. at leat one active session per sample, but are not well suited for low database activity periods.

We will modify the following views in order to handle high database activity periods as well as low database activity periods.

Assumption:

  • Those views are based on a sampling period interval set to 2 seconds.

View v$aas_light_sampling_sessions (Part XXI)

CREATE OR REPLACE VIEW v$aas_light_sampling_sessions
AS
SELECT sample_yyyymmddhhmi,
       SUBSTR(sample_yyyymmddhhmi,9,2) || ':' || SUBSTR(sample_yyyymmddhhmi,11,2) BEGIN_TIME,
       aas1                                                                 C_CPU,
       aas1+aas2                                                            C_OTHER,
       aas1+aas2+aas3                                                       C_APPLICATION,
       aas1+aas2+aas3+aas4                                                  C_CONFIGURATION,
       aas1+aas2+aas3+aas4+aas5                                             C_ADMINISTRATIVE,
       aas1+aas2+aas3+aas4+aas5+aas6                                        C_CONCURRENCY,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7                                   C_COMMIT,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8                              C_NETWORK,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9                         C_USER_IO,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10                   C_SYSTEM_IO,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11             C_SCHEDULER,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12       C_CLUSTER,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12+aas13 C_QUEUEING,
       MAX(CEIL(aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12+aas13)) OVER() MAX_AAS
FROM
   (SELECT sample_yyyymmddhhmi,
           TRUNC((count_cpu/(nb_samples)),3)            aas1,  --aas_cpu,
           TRUNC((count_other/(nb_samples)),3)          aas2,  --aas_other,
           TRUNC((count_application/(nb_samples)),3)    aas3,  --aas_application,
           TRUNC((count_configuration/(nb_samples)),3)  aas4,  --aas_configuration,
           TRUNC((count_administrative/(nb_samples)),3) aas5,  --aas_administrative,
           TRUNC((count_concurrency/(nb_samples)),3)    aas6,  --aas_concurrency,
           TRUNC((count_commit/(nb_samples)),3)         aas7,  --aas_commit,
           TRUNC((count_network/(nb_samples)),3)        aas8,  --aas_network,
           TRUNC((count_user_io/(nb_samples)),3)        aas9,  --aas_user_io,
           TRUNC((count_system_io/(nb_samples)),3)      aas10, --aas_system_io,
           TRUNC((count_scheduler/(nb_samples)),3)      aas11, --aas_scheduler,
           TRUNC((count_cluster/(nb_samples)),3)        aas12, --aas_cluster,
           TRUNC((count_queueing/(nb_samples)),3)       aas13  --aas_queueing    
    FROM 
       (SELECT NVL(co_base_qry.sample_yyyymmddhhmi,time_window.start_time) sample_yyyymmddhhmi,
               NVL(co_base_qry.nb_samples,1)           nb_samples,
               NVL(co_base_qry.count_cpu,0)            count_cpu,
               NVL(co_base_qry.count_other,0)          count_other,
               NVL(co_base_qry.count_application,0)    count_application,
               NVL(co_base_qry.count_configuration,0)  count_configuration,
               NVL(co_base_qry.count_administrative,0) count_administrative,
               NVL(co_base_qry.count_concurrency,0)    count_concurrency,
               NVL(co_base_qry.count_commit,0)         count_commit,
               NVL(co_base_qry.count_network,0)        count_network,
               NVL(co_base_qry.count_user_io,0)        count_user_io,
               NVL(co_base_qry.count_system_io,0)      count_system_io,
               NVL(co_base_qry.count_scheduler,0)      count_scheduler,
               NVL(co_base_qry.count_cluster,0)        count_cluster,
               NVL(co_base_qry.count_queueing,0)       count_queueing
        FROM
           (SELECT TO_CHAR(SYSDATE - (LEVEL/24/60),'YYYYMMDDHH24MI') start_time
            FROM DUAL 
            CONNECT BY LEVEL <= 61
            ) time_window
        LEFT OUTER JOIN 
           (SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') sample_yyyymmddhhmi,
                   30 nb_samples,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),-1,1)) count_cpu,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),0,1))  count_other,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),1,1))  count_application,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),2,1))  count_configuration,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),3,1))  count_administrative,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),4,1))  count_concurrency,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),5,1))  count_commit,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),7,1))  count_network,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),8,1))  count_user_io,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),9,1))  count_system_io,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),10,1)) count_scheduler,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),11,1)) count_cluster,
                   COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),12,1)) count_queueing
            FROM lss$_sampling_session
            GROUP BY TO_CHAR(sample_time,'YYYYMMDDHH24MI')
            ) co_base_qry
          ON time_window.start_time=co_base_qry.sample_yyyymmddhhmi
       )
  );

View v$cdb_pdb_aas_lss (Part XXII)

CREATE OR REPLACE VIEW v$cdb_pdb_aas_lss
AS          
SELECT sample_yyyymmddhhmi,
       SUBSTR(sample_yyyymmddhhmi,9,2) || ':' || SUBSTR(sample_yyyymmddhhmi,11,2)                                        BEGIN_TIME,
       aas_cpu0                                                                                                          C_CONT0_CPU,
       aas_cpu0+aas_wait0                                                                                                C_CONT0_WAIT,
       aas_cpu0+aas_wait0+aas_cpu1                                                                                       C_CONT1_CPU,
       aas_cpu0+aas_wait0+aas_cpu1+aas_wait1                                                                             C_CONT1_WAIT,
       aas_cpu0+aas_wait0+aas_cpu1+aas_wait1+aas_cpu2                                                                    C_CONT2_CPU,
       aas_cpu0+aas_wait0+aas_cpu1+aas_wait1+aas_cpu2+aas_wait2                                                          C_CONT2_WAIT,
       aas_cpu0+aas_wait0+aas_cpu1+aas_wait1+aas_cpu2+aas_wait2+aas_cpu3                                                 C_CONT3_CPU,
       aas_cpu0+aas_wait0+aas_cpu1+aas_wait1+aas_cpu2+aas_wait2+aas_cpu3+aas_wait3                                       C_CONT3_WAIT,
       aas_cpu0+aas_wait0+aas_cpu1+aas_wait1+aas_cpu2+aas_wait2+aas_cpu3+aas_wait3+aas_cpu4                              C_CONT4_CPU,
       aas_cpu0+aas_wait0+aas_cpu1+aas_wait1+aas_cpu2+aas_wait2+aas_cpu3+aas_wait3+aas_cpu4+aas_wait4                    C_CONT4_WAIT,
       aas_cpu0+aas_wait0+aas_cpu1+aas_wait1+aas_cpu2+aas_wait2+aas_cpu3+aas_wait3+aas_cpu4+aas_wait4+aas_cpu5           C_CONT5_CPU,
       aas_cpu0+aas_wait0+aas_cpu1+aas_wait1+aas_cpu2+aas_wait2+aas_cpu3+aas_wait3+aas_cpu4+aas_wait4+aas_cpu5+aas_wait5 C_CONT5_WAIT,
       MAX(CEIL(aas_cpu0+aas_wait0+aas_cpu1+aas_wait1+aas_cpu2+aas_wait2+aas_cpu3+aas_wait3+aas_cpu4+aas_wait4+aas_cpu5+aas_wait5)) OVER() MAX_CONT_AAS
FROM 
   (SELECT NVL(co_base_qry.sample_yyyymmddhhmi,time_window.start_time) sample_yyyymmddhhmi,
           NVL(co_base_qry.sum_aas_cpu0,0)   aas_cpu0,
           NVL(co_base_qry.sum_aas_wait0,0)  aas_wait0,
           NVL(co_base_qry.sum_aas_cpu1,0)   aas_cpu1,
           NVL(co_base_qry.sum_aas_wait1,0)  aas_wait1,
           NVL(co_base_qry.sum_aas_cpu2,0)   aas_cpu2,
           NVL(co_base_qry.sum_aas_wait2,0)  aas_wait2,
           NVL(co_base_qry.sum_aas_cpu3,0)   aas_cpu3,
           NVL(co_base_qry.sum_aas_wait3,0)  aas_wait3,
           NVL(co_base_qry.sum_aas_cpu4,0)   aas_cpu4,
           NVL(co_base_qry.sum_aas_wait4,0)  aas_wait4,
           NVL(co_base_qry.sum_aas_cpu5,0)   aas_cpu5,
           NVL(co_base_qry.sum_aas_wait5,0)  aas_wait5
    FROM 
       (SELECT TO_CHAR(SYSDATE - (LEVEL/24/60),'YYYYMMDDHH24MI') start_time
        FROM DUAL 
        CONNECT BY LEVEL <= 61
       ) time_window
    LEFT OUTER JOIN 
       (SELECT sample_yyyymmddhhmi,
               SUM(aas_cpu0)  sum_aas_cpu0,
               SUM(aas_wait0) sum_aas_wait0,
               SUM(aas_cpu1)  sum_aas_cpu1,
               SUM(aas_wait1) sum_aas_wait1,
               SUM(aas_cpu2)  sum_aas_cpu2,
               SUM(aas_wait2) sum_aas_wait2,
               SUM(aas_cpu3)  sum_aas_cpu3,
               SUM(aas_wait3) sum_aas_wait3,
               SUM(aas_cpu4)  sum_aas_cpu4,
               SUM(aas_wait4) sum_aas_wait4,
               SUM(aas_cpu5)  sum_aas_cpu5,
               SUM(aas_wait5) sum_aas_wait5
        FROM 
           (SELECT sample_yyyymmddhhmi,
                   CASE con_id
                      WHEN 0 THEN TRUNC(count_cpu/(nb_samples),3)
                      ELSE 0
                   END aas_cpu0,
                   CASE con_id
                      WHEN 0 THEN TRUNC(count_wait/(nb_samples),3)
                      ELSE 0
                   END aas_wait0,
                   CASE con_id
                      WHEN 1 THEN TRUNC(count_cpu/(nb_samples),3)
                      ELSE 0
                   END aas_cpu1,
                   CASE con_id
                      WHEN 1 THEN TRUNC(count_wait/(nb_samples),3)
                      ELSE 0
                   END aas_wait1,
                   CASE con_id
                      WHEN 3 THEN TRUNC(count_cpu/(nb_samples),3)
                      ELSE 0
                   END aas_cpu2,
                   CASE con_id
                      WHEN 3 THEN TRUNC(count_wait/(nb_samples),3)
                      ELSE 0
                   END aas_wait2,
                   CASE con_id
                      WHEN 4 THEN TRUNC(count_cpu/(nb_samples),3)
                      ELSE 0
                   END aas_cpu3,
                   CASE con_id
                      WHEN 4 THEN TRUNC(count_wait/(nb_samples),3)
                      ELSE 0
                   END aas_wait3,
                   CASE con_id
                      WHEN 5 THEN TRUNC(count_cpu/(nb_samples),3)
                      ELSE 0
                   END aas_cpu4,
                   CASE con_id
                      WHEN 5 THEN TRUNC(count_wait/(nb_samples),3)
                      ELSE 0
                   END aas_wait4,
                   CASE con_id
                      WHEN 6 THEN TRUNC(count_cpu/(nb_samples),3)
                      ELSE 0
                   END aas_cpu5,
                   CASE con_id
                      WHEN 6 THEN TRUNC(count_wait/(nb_samples),3)
                      ELSE 0
                   END aas_wait5
            FROM 
               (SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') sample_yyyymmddhhmi,
                       con_id,
                       30 nb_samples,
                       COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),-1,1)) count_cpu,
                       COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),0,1,1,1,2,1,3,1,4,1,5,1,7,1,8,1,9,1,10,1,11,1,12,1)) count_wait
                FROM lss$_sampling_session
                GROUP BY con_id,
                        TO_CHAR(sample_time,'YYYYMMDDHH24MI')
                )
           ) GROUP BY sample_yyyymmddhhmi
       ) co_base_qry
      ON time_window.start_time=co_base_qry.sample_yyyymmddhhmi
   );

View v$top_activity_session_lss (Part XXIII)

CREATE OR REPLACE VIEW v$top_activity_session_lss
AS
SELECT sid,
       serial#,
       user#,
       user_program,
       user_con_id,
       count_total,
       aas1                                                                 C_CPU,
       aas1+aas2                                                            C_OTHER,
       aas1+aas2+aas3                                                       C_APPLICATION,
       aas1+aas2+aas3+aas4                                                  C_CONFIGURATION,
       aas1+aas2+aas3+aas4+aas5                                             C_ADMINISTRATIVE,
       aas1+aas2+aas3+aas4+aas5+aas6                                        C_CONCURRENCY,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7                                   C_COMMIT,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8                              C_NETWORK,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9                         C_USER_IO,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10                   C_SYSTEM_IO,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11             C_SCHEDULER,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12       C_CLUSTER,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12+aas13 C_QUEUEING,
       MAX(aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12+aas13) OVER() MAX_AAS
FROM 
   (SELECT sid,
           serial#,
           max_user#   user#,
           max_program user_program,
           max_con_id  user_con_id,
           TRUNC((count_cpu/(max_samples)),3)            aas1,  --aas_cpu
           TRUNC((count_other/(max_samples)),3)          aas2,  --aas_other
           TRUNC((count_application/(max_samples)),3)    aas3,  --aas_application
           TRUNC((count_configuration/(max_samples)),3)  aas4,  --aas_configuration
           TRUNC((count_administrative/(max_samples)),3) aas5,  --aas_administrative
           TRUNC((count_concurrency/(max_samples)),3)    aas6,  --aas_concurrency
           TRUNC((count_commit/(max_samples)),3)         aas7,  --aas_commit
           TRUNC((count_network/(max_samples)),3)        aas8,  --aas_network
           TRUNC((count_user_io/(max_samples)),3)        aas9,  --aas_user_io
           TRUNC((count_system_io/(max_samples)),3)      aas10, --aas_system_io
           TRUNC((count_scheduler/(max_samples)),3)      aas11, --aas_scheduler
           TRUNC((count_cluster/(max_samples)),3)        aas12, --aas_cluster
           TRUNC((count_queueing/(max_samples)),3)       aas13, --aas_queueing 
           count_total
    FROM
       (SELECT sid,
               serial#,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),-1,1)) count_cpu,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),0,1))  count_other,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),1,1))  count_application,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),2,1))  count_configuration,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),3,1))  count_administrative,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),4,1))  count_concurrency,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),5,1))  count_commit,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),7,1))  count_network,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),8,1))  count_user_io,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),9,1))  count_system_io,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),10,1)) count_scheduler,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),11,1)) count_cluster,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),12,1)) count_queueing,
               COUNT(*)                             count_total,
               300                                  max_samples,
               MAX(user#)                           max_user#,
               MAX(program)                         max_program,
               MAX(con_id)                          max_con_id
        FROM lss$_sampling_session
        WHERE sample_time >= SYSDATE -(10/24/60)
        GROUP BY sid,
                 serial#
        ORDER BY count_total DESC
        FETCH FIRST 20 ROWS ONLY
        )
   );

View v$session_activity_lss (Part XXIV)

CREATE OR REPLACE VIEW v$session_activity_lss
AS
WITH session_events AS
   (
   SELECT event,
          COUNT(*) count_event, 
          RANK() OVER (ORDER BY COUNT(*) DESC, EVENT) rank_event 
   FROM lss$_sampling_session
   WHERE SID = get_current_session
     AND sample_time >= SYSDATE -(1/24) 
     AND session_state <> 'C'
   GROUP BY event
   ORDER BY count_event DESC
   FETCH FIRST 12 ROWS ONLY
   )
SELECT sample_yyyymmddhhmi,
       SUBSTR(sample_yyyymmddhhmi,9,2) || ':' || SUBSTR(sample_yyyymmddhhmi,11,2) BEGIN_TIME,
       avge1                                                                             C_EVENT0,
       avge1+avge2                                                                       C_EVENT1,
       avge1+avge2+avge3                                                                 C_EVENT2,
       avge1+avge2+avge3+avge4                                                           C_EVENT3,
       avge1+avge2+avge3+avge4+avge5                                                     C_EVENT4,
       avge1+avge2+avge3+avge4+avge5+avge6                                               C_EVENT5,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7                                         C_EVENT6,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8                                   C_EVENT7,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9                             C_EVENT8,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10                      C_EVENT9,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11               C_EVENT10,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11+avge12        C_EVENT11,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11+avge12+avge13 C_EVENT12,
       MAX(avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11+avge12+avge13) OVER() MAX_EVENT,
       (SELECT get_current_session FROM DUAL) session_id,
       MAX(event_name0)  OVER() EVENT_NAME0,
       MAX(event_name1)  OVER() EVENT_NAME1,
       MAX(event_name2)  OVER() EVENT_NAME2,
       MAX(event_name3)  OVER() EVENT_NAME3,
       MAX(event_name4)  OVER() EVENT_NAME4,
       MAX(event_name5)  OVER() EVENT_NAME5,
       MAX(event_name6)  OVER() EVENT_NAME6,
       MAX(event_name7)  OVER() EVENT_NAME7,
       MAX(event_name8)  OVER() EVENT_NAME8,
       MAX(event_name9)  OVER() EVENT_NAME9,
       MAX(event_name10) OVER() EVENT_NAME10,
       MAX(event_name11) OVER() EVENT_NAME11,
       MAX(event_name12) OVER() EVENT_NAME12
FROM
   (SELECT sample_yyyymmddhhmi,
           TRUNC((count_event0/(nb_samples)),3)  avge1,  
           TRUNC((count_event1/(nb_samples)),3)  avge2,  
           TRUNC((count_event2/(nb_samples)),3)  avge3, 
           TRUNC((count_event3/(nb_samples)),3)  avge4,  
           TRUNC((count_event4/(nb_samples)),3)  avge5,  
           TRUNC((count_event5/(nb_samples)),3)  avge6,  
           TRUNC((count_event6/(nb_samples)),3)  avge7,  
           TRUNC((count_event7/(nb_samples)),3)  avge8,  
           TRUNC((count_event8/(nb_samples)),3)  avge9,  
           TRUNC((count_event9/(nb_samples)),3)  avge10, 
           TRUNC((count_event10/(nb_samples)),3) avge11, 
           TRUNC((count_event11/(nb_samples)),3) avge12, 
           TRUNC((count_event12/(nb_samples)),3) avge13,  
           event_name0,
           event_name1,
           event_name2,
           event_name3,
           event_name4,
           event_name5,
           event_name6,
           event_name7,
           event_name8,
           event_name9,
           event_name10,
           event_name11,
           event_name12
    FROM 
       (SELECT NVL(co_base_qry.sample_yyyymmddhhmi,time_window.start_time) sample_yyyymmddhhmi,
               NVL(co_base_qry.nb_samples,1)    nb_samples,
               NVL(co_base_qry.count_event0,0)  count_event0,
               NVL(co_base_qry.count_event1,0)  count_event1,
               NVL(co_base_qry.count_event2,0)  count_event2,
               NVL(co_base_qry.count_event3,0)  count_event3,
               NVL(co_base_qry.count_event4,0)  count_event4,
               NVL(co_base_qry.count_event5,0)  count_event5,
               NVL(co_base_qry.count_event6,0)  count_event6,
               NVL(co_base_qry.count_event7,0)  count_event7,
               NVL(co_base_qry.count_event8,0)  count_event8,
               NVL(co_base_qry.count_event9,0)  count_event9,
               NVL(co_base_qry.count_event10,0) count_event10,
               NVL(co_base_qry.count_event11,0) count_event11,
               NVL(co_base_qry.count_event12,0) count_event12,
               co_base_qry.event_name0,
               co_base_qry.event_name1,
               co_base_qry.event_name2,
               co_base_qry.event_name3,
               co_base_qry.event_name4,
               co_base_qry.event_name5,
               co_base_qry.event_name6,
               co_base_qry.event_name7,
               co_base_qry.event_name8,
               co_base_qry.event_name9,
               co_base_qry.event_name10,
               co_base_qry.event_name11,
               co_base_qry.event_name12
        FROM
           (SELECT TO_CHAR(SYSDATE - (LEVEL/24/60),'YYYYMMDDHH24MI') start_time
            FROM DUAL 
            CONNECT BY LEVEL <= 61
            ) time_window
        LEFT OUTER JOIN 
           (SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') sample_yyyymmddhhmi,
                   30 nb_samples,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),-1,1)) count_event0,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,1))  count_event1,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,1))  count_event2,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,1))  count_event3,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,1))  count_event4,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,1))  count_event5,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,1))  count_event6,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,1))  count_event7,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,1))  count_event8,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,1))  count_event9,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,1)) count_event10,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,1)) count_event11,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,1)) count_event12,
                   'cpu'    event_name0,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,sess_event.event))  event_name1,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,sess_event.event))  event_name2,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,sess_event.event))  event_name3,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,sess_event.event))  event_name4,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,sess_event.event))  event_name5,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,sess_event.event))  event_name6,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,sess_event.event))  event_name7,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,sess_event.event))  event_name8,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,sess_event.event))  event_name9,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,sess_event.event)) event_name10,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,sess_event.event)) event_name11,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,sess_event.event)) event_name12
            FROM lss$_sampling_session lss
            LEFT OUTER JOIN session_events sess_event
              ON sess_event.event = lss.event
            WHERE lss.sid = get_current_session
            GROUP BY TO_CHAR(sample_time,'YYYYMMDDHH24MI')
            ) co_base_qry
          ON time_window.start_time=co_base_qry.sample_yyyymmddhhmi
       )
  );

Remarks:

  • The views v$aas_light_sampling_sessions, v$cdb_pdb_aas_lss, v$session_activity_lss and v$top_activity_session_lss are created from the CDB$ROOT container in the C##LSS schema,
  • The view v$session_activity30s_lss (Part XXV) will be updated shortly.

Errata

  • In the view v$top_activity_session_lss, the “max_samples” column value should be 300 instead of 30 (the view has been fixed to reflect this change).

Generating SVG graphics with SQL*Plus – Part XXV – Stacked area graph – Session Activity – Light Sampling Sessions – Update

Scope

In this post we will focus on tracking session activity at CDB/PDB level and on increasing the accuracy of the graph. The previous post displays the consolidated session id at the instance level. If we want to track a session at the CDB/PDB level we need:

  • A session id,
  • A serial#,
  • A container id.

Function get_current_session

We will slightly modify the function get_current_session in order to get the triplet ‘[session_id],[serial#],[con_id]’:

CREATE OR REPLACE FUNCTION get_current_session RETURN VARCHAR2
AS 
   v_param_value lss$parameter.parameter_value%TYPE;
BEGIN

   SELECT parameter_value
   INTO v_param_value
   FROM lss$parameter
   WHERE parameter_name = 'current_session';
   
   RETURN v_param_value;
   
   EXCEPTION
      WHEN TOO_MANY_ROWS THEN
         RETURN '<UNKNOWN>';
      WHEN NO_DATA_FOUND THEN
         RETURN '<UNKNOWN>';
      WHEN OTHERS THEN
         RAISE;
         
END get_current_session;

Basically the triplet will be stored in the table lss$parameter as a string.

Increase graph accuracy

Instead of counting the events on a period of time of one minute we will count them on a period of time of 30 seconds. We will create a new view v$session_activity30s_lss in order to display the session activity every 30 seconds. The starting point will be the view v$session_activity_lss.

View creation – Step 1

The differences with the previous post are:

WITH session_events AS
   (
   SELECT event,
          COUNT(*) count_event, 
          RANK() OVER (ORDER BY COUNT(*) DESC, EVENT) rank_event 
   FROM lss$_sampling_session
   WHERE TO_CHAR(sid) || ',' || TO_CHAR(serial#) || ',' || TO_CHAR(con_id) = get_current_session
     AND sample_time >= SYSDATE -(1/24) 
     AND session_state <> 'C'
   GROUP BY event
   ORDER BY count_event DESC
   FETCH FIRST 12 ROWS ONLY
   )

The session identifier is now ‘[session_id],[serial#],[con_id]’.

View creation – Step 2

The differences with the previous post are:

            SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(sample_time,'SS'))/30)) sample_yyyymmddhhmi30s,
                   MAX(sample_id) - MIN(sample_id) nb_samples,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),-1,1)) count_event0,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,1))  count_event1,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,1))  count_event2,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,1))  count_event3,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,1))  count_event4,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,1))  count_event5,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,1))  count_event6,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,1))  count_event7,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,1))  count_event8,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,1))  count_event9,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,1)) count_event10,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,1)) count_event11,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,1)) count_event12,
                   'cpu'    event_name0,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,sess_event.event))  event_name1,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,sess_event.event))  event_name2,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,sess_event.event))  event_name3,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,sess_event.event))  event_name4,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,sess_event.event))  event_name5,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,sess_event.event))  event_name6,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,sess_event.event))  event_name7,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,sess_event.event))  event_name8,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,sess_event.event))  event_name9,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,sess_event.event)) event_name10,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,sess_event.event)) event_name11,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,sess_event.event)) event_name12
            FROM lss$_sampling_session lss
            LEFT OUTER JOIN session_events sess_event
              ON sess_event.event = lss.event
            WHERE TO_CHAR(lss.sid) || ',' || TO_CHAR(lss.serial#) || ',' || TO_CHAR(lss.con_id) = get_current_session
            GROUP BY TO_CHAR(sample_time,'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(sample_time,'SS'))/30))

The session identifier is now ‘[session_id],[serial#],[con_id]’. In order to count the events every 30 seconds, we will define the first 30 seconds of a minute as “0” and the last 30 seconds of a minute as “1”. The time dimension is now called sample_yyyymmddhhmi30s.

View creation – Step 3

The differences with the previous post are:

        SELECT NVL(co_base_qry.sample_yyyymmddhhmi30s,time_window.start_time) sample_yyyymmddhhmi30s,
               NVL(co_base_qry.nb_samples,1)    nb_samples,
               NVL(co_base_qry.count_event0,0)  count_event0,
               NVL(co_base_qry.count_event1,0)  count_event1,
               NVL(co_base_qry.count_event2,0)  count_event2,
               NVL(co_base_qry.count_event3,0)  count_event3,
               NVL(co_base_qry.count_event4,0)  count_event4,
               NVL(co_base_qry.count_event5,0)  count_event5,
               NVL(co_base_qry.count_event6,0)  count_event6,
               NVL(co_base_qry.count_event7,0)  count_event7,
               NVL(co_base_qry.count_event8,0)  count_event8,
               NVL(co_base_qry.count_event9,0)  count_event9,
               NVL(co_base_qry.count_event10,0) count_event10,
               NVL(co_base_qry.count_event11,0) count_event11,
               NVL(co_base_qry.count_event12,0) count_event12,
               co_base_qry.event_name0,
               co_base_qry.event_name1,
               co_base_qry.event_name2,
               co_base_qry.event_name3,
               co_base_qry.event_name4,
               co_base_qry.event_name5,
               co_base_qry.event_name6,
               co_base_qry.event_name7,
               co_base_qry.event_name8,
               co_base_qry.event_name9,
               co_base_qry.event_name10,
               co_base_qry.event_name11,
               co_base_qry.event_name12
        FROM
           (SELECT TO_CHAR(SYSDATE - ((LEVEL*30)/24/60/60),'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(SYSDATE - ((LEVEL*30)/24/60/60),'SS'))/30)) start_time
            FROM DUAL 
            CONNECT BY LEVEL <= 122
            ) time_window
        LEFT OUTER JOIN 
           (SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(sample_time,'SS'))/30)) sample_yyyymmddhhmi30s,
                   MAX(sample_id) - MIN(sample_id) nb_samples,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),-1,1)) count_event0,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,1))  count_event1,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,1))  count_event2,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,1))  count_event3,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,1))  count_event4,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,1))  count_event5,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,1))  count_event6,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,1))  count_event7,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,1))  count_event8,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,1))  count_event9,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,1)) count_event10,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,1)) count_event11,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,1)) count_event12,
                   'cpu'    event_name0,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,sess_event.event))  event_name1,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,sess_event.event))  event_name2,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,sess_event.event))  event_name3,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,sess_event.event))  event_name4,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,sess_event.event))  event_name5,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,sess_event.event))  event_name6,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,sess_event.event))  event_name7,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,sess_event.event))  event_name8,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,sess_event.event))  event_name9,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,sess_event.event)) event_name10,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,sess_event.event)) event_name11,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,sess_event.event)) event_name12
            FROM lss$_sampling_session lss
            LEFT OUTER JOIN session_events sess_event
              ON sess_event.event = lss.event
            WHERE TO_CHAR(lss.sid) || ',' || TO_CHAR(lss.serial#) || ',' || TO_CHAR(lss.con_id) = get_current_session
            GROUP BY TO_CHAR(sample_time,'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(sample_time,'SS'))/30))
            ) co_base_qry
          ON time_window.start_time=co_base_qry.sample_yyyymmddhhmi30s

The time_windows query has changed in order to have 30 second intervals.

View creation – Step 4

The differences with the previous post are:

    SELECT sample_yyyymmddhhmi30s,
           TRUNC((count_event0/(nb_samples+1)),3)  avge1,  
           TRUNC((count_event1/(nb_samples+1)),3)  avge2,  
           TRUNC((count_event2/(nb_samples+1)),3)  avge3, 
           TRUNC((count_event3/(nb_samples+1)),3)  avge4,  
           TRUNC((count_event4/(nb_samples+1)),3)  avge5,  
           TRUNC((count_event5/(nb_samples+1)),3)  avge6,  
           TRUNC((count_event6/(nb_samples+1)),3)  avge7,  
           TRUNC((count_event7/(nb_samples+1)),3)  avge8,  
           TRUNC((count_event8/(nb_samples+1)),3)  avge9,  
           TRUNC((count_event9/(nb_samples+1)),3)  avge10, 
           TRUNC((count_event10/(nb_samples+1)),3) avge11, 
           TRUNC((count_event11/(nb_samples+1)),3) avge12, 
           TRUNC((count_event12/(nb_samples+1)),3) avge13,  
           event_name0,
           event_name1,
           event_name2,
           event_name3,
           event_name4,
           event_name5,
           event_name6,
           event_name7,
           event_name8,
           event_name9,
           event_name10,
           event_name11,
           event_name12
    FROM 
       (SELECT NVL(co_base_qry.sample_yyyymmddhhmi30s,time_window.start_time) sample_yyyymmddhhmi30s,
               NVL(co_base_qry.nb_samples,1)    nb_samples,
               NVL(co_base_qry.count_event0,0)  count_event0,
               NVL(co_base_qry.count_event1,0)  count_event1,
               NVL(co_base_qry.count_event2,0)  count_event2,
               NVL(co_base_qry.count_event3,0)  count_event3,
               NVL(co_base_qry.count_event4,0)  count_event4,
               NVL(co_base_qry.count_event5,0)  count_event5,
               NVL(co_base_qry.count_event6,0)  count_event6,
               NVL(co_base_qry.count_event7,0)  count_event7,
               NVL(co_base_qry.count_event8,0)  count_event8,
               NVL(co_base_qry.count_event9,0)  count_event9,
               NVL(co_base_qry.count_event10,0) count_event10,
               NVL(co_base_qry.count_event11,0) count_event11,
               NVL(co_base_qry.count_event12,0) count_event12,
               co_base_qry.event_name0,
               co_base_qry.event_name1,
               co_base_qry.event_name2,
               co_base_qry.event_name3,
               co_base_qry.event_name4,
               co_base_qry.event_name5,
               co_base_qry.event_name6,
               co_base_qry.event_name7,
               co_base_qry.event_name8,
               co_base_qry.event_name9,
               co_base_qry.event_name10,
               co_base_qry.event_name11,
               co_base_qry.event_name12
        FROM
           (SELECT TO_CHAR(SYSDATE - ((LEVEL*30)/24/60/60),'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(SYSDATE - ((LEVEL*30)/24/60/60),'SS'))/30)) start_time
            FROM DUAL 
            CONNECT BY LEVEL <= 122
            ) time_window
        LEFT OUTER JOIN 
           (SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(sample_time,'SS'))/30)) sample_yyyymmddhhmi30s,
                   MAX(sample_id) - MIN(sample_id) nb_samples,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),-1,1)) count_event0,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,1))  count_event1,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,1))  count_event2,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,1))  count_event3,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,1))  count_event4,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,1))  count_event5,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,1))  count_event6,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,1))  count_event7,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,1))  count_event8,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,1))  count_event9,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,1)) count_event10,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,1)) count_event11,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,1)) count_event12,
                   'cpu'    event_name0,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,sess_event.event))  event_name1,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,sess_event.event))  event_name2,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,sess_event.event))  event_name3,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,sess_event.event))  event_name4,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,sess_event.event))  event_name5,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,sess_event.event))  event_name6,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,sess_event.event))  event_name7,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,sess_event.event))  event_name8,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,sess_event.event))  event_name9,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,sess_event.event)) event_name10,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,sess_event.event)) event_name11,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,sess_event.event)) event_name12
            FROM lss$_sampling_session lss
            LEFT OUTER JOIN session_events sess_event
              ON sess_event.event = lss.event
            WHERE TO_CHAR(lss.sid) || ',' || TO_CHAR(lss.serial#) || ',' || TO_CHAR(lss.con_id) = get_current_session
            GROUP BY TO_CHAR(sample_time,'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(sample_time,'SS'))/30))
            ) co_base_qry
          ON time_window.start_time=co_base_qry.sample_yyyymmddhhmi30s
       )

View creation – Step 5

The differences with the previous post are:

CREATE OR REPLACE VIEW v$session_activity30s_lss
AS
WITH session_events AS
   (
   SELECT event,
          COUNT(*) count_event, 
          RANK() OVER (ORDER BY COUNT(*) DESC, EVENT) rank_event 
   FROM lss$_sampling_session
   WHERE TO_CHAR(sid) || ',' || TO_CHAR(serial#) || ',' || TO_CHAR(con_id) = get_current_session
     AND sample_time >= SYSDATE -(1/24) 
     AND session_state <> 'C'
   GROUP BY event
   ORDER BY count_event DESC
   FETCH FIRST 12 ROWS ONLY
   )
SELECT sample_yyyymmddhhmi30s,
       SUBSTR(sample_yyyymmddhhmi30s,9,2) || ':' || SUBSTR(sample_yyyymmddhhmi30s,11,2) BEGIN_TIME,
       avge1                                                                             C_EVENT0,
       avge1+avge2                                                                       C_EVENT1,
       avge1+avge2+avge3                                                                 C_EVENT2,
       avge1+avge2+avge3+avge4                                                           C_EVENT3,
       avge1+avge2+avge3+avge4+avge5                                                     C_EVENT4,
       avge1+avge2+avge3+avge4+avge5+avge6                                               C_EVENT5,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7                                         C_EVENT6,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8                                   C_EVENT7,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9                             C_EVENT8,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10                      C_EVENT9,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11               C_EVENT10,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11+avge12        C_EVENT11,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11+avge12+avge13 C_EVENT12,
       MAX(CEIL(avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11+avge12+avge13)) OVER() MAX_EVENT,
       (SELECT get_current_session FROM DUAL) session_id,
       MAX(event_name0)  OVER() EVENT_NAME0,
       MAX(event_name1)  OVER() EVENT_NAME1,
       MAX(event_name2)  OVER() EVENT_NAME2,
       MAX(event_name3)  OVER() EVENT_NAME3,
       MAX(event_name4)  OVER() EVENT_NAME4,
       MAX(event_name5)  OVER() EVENT_NAME5,
       MAX(event_name6)  OVER() EVENT_NAME6,
       MAX(event_name7)  OVER() EVENT_NAME7,
       MAX(event_name8)  OVER() EVENT_NAME8,
       MAX(event_name9)  OVER() EVENT_NAME9,
       MAX(event_name10) OVER() EVENT_NAME10,
       MAX(event_name11) OVER() EVENT_NAME11,
       MAX(event_name12) OVER() EVENT_NAME12
FROM
   (SELECT sample_yyyymmddhhmi30s,
           TRUNC((count_event0/(nb_samples+1)),3)  avge1,  
           TRUNC((count_event1/(nb_samples+1)),3)  avge2,  
           TRUNC((count_event2/(nb_samples+1)),3)  avge3, 
           TRUNC((count_event3/(nb_samples+1)),3)  avge4,  
           TRUNC((count_event4/(nb_samples+1)),3)  avge5,  
           TRUNC((count_event5/(nb_samples+1)),3)  avge6,  
           TRUNC((count_event6/(nb_samples+1)),3)  avge7,  
           TRUNC((count_event7/(nb_samples+1)),3)  avge8,  
           TRUNC((count_event8/(nb_samples+1)),3)  avge9,  
           TRUNC((count_event9/(nb_samples+1)),3)  avge10, 
           TRUNC((count_event10/(nb_samples+1)),3) avge11, 
           TRUNC((count_event11/(nb_samples+1)),3) avge12, 
           TRUNC((count_event12/(nb_samples+1)),3) avge13,  
           event_name0,
           event_name1,
           event_name2,
           event_name3,
           event_name4,
           event_name5,
           event_name6,
           event_name7,
           event_name8,
           event_name9,
           event_name10,
           event_name11,
           event_name12
    FROM 
       (SELECT NVL(co_base_qry.sample_yyyymmddhhmi30s,time_window.start_time) sample_yyyymmddhhmi30s,
               NVL(co_base_qry.nb_samples,1)    nb_samples,
               NVL(co_base_qry.count_event0,0)  count_event0,
               NVL(co_base_qry.count_event1,0)  count_event1,
               NVL(co_base_qry.count_event2,0)  count_event2,
               NVL(co_base_qry.count_event3,0)  count_event3,
               NVL(co_base_qry.count_event4,0)  count_event4,
               NVL(co_base_qry.count_event5,0)  count_event5,
               NVL(co_base_qry.count_event6,0)  count_event6,
               NVL(co_base_qry.count_event7,0)  count_event7,
               NVL(co_base_qry.count_event8,0)  count_event8,
               NVL(co_base_qry.count_event9,0)  count_event9,
               NVL(co_base_qry.count_event10,0) count_event10,
               NVL(co_base_qry.count_event11,0) count_event11,
               NVL(co_base_qry.count_event12,0) count_event12,
               co_base_qry.event_name0,
               co_base_qry.event_name1,
               co_base_qry.event_name2,
               co_base_qry.event_name3,
               co_base_qry.event_name4,
               co_base_qry.event_name5,
               co_base_qry.event_name6,
               co_base_qry.event_name7,
               co_base_qry.event_name8,
               co_base_qry.event_name9,
               co_base_qry.event_name10,
               co_base_qry.event_name11,
               co_base_qry.event_name12
        FROM
           (SELECT TO_CHAR(SYSDATE - ((LEVEL*30)/24/60/60),'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(SYSDATE - ((LEVEL*30)/24/60/60),'SS'))/30)) start_time
            FROM DUAL 
            CONNECT BY LEVEL <= 122
            ) time_window
        LEFT OUTER JOIN 
           (SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(sample_time,'SS'))/30)) sample_yyyymmddhhmi30s,
                   MAX(sample_id) - MIN(sample_id) nb_samples,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),-1,1)) count_event0,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,1))  count_event1,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,1))  count_event2,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,1))  count_event3,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,1))  count_event4,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,1))  count_event5,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,1))  count_event6,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,1))  count_event7,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,1))  count_event8,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,1))  count_event9,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,1)) count_event10,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,1)) count_event11,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,1)) count_event12,
                   'cpu'    event_name0,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,sess_event.event))  event_name1,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,sess_event.event))  event_name2,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,sess_event.event))  event_name3,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,sess_event.event))  event_name4,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,sess_event.event))  event_name5,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,sess_event.event))  event_name6,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,sess_event.event))  event_name7,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,sess_event.event))  event_name8,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,sess_event.event))  event_name9,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,sess_event.event)) event_name10,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,sess_event.event)) event_name11,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,sess_event.event)) event_name12
            FROM lss$_sampling_session lss
            LEFT OUTER JOIN session_events sess_event
              ON sess_event.event = lss.event
            WHERE TO_CHAR(lss.sid) || ',' || TO_CHAR(lss.serial#) || ',' || TO_CHAR(lss.con_id) = get_current_session
            GROUP BY TO_CHAR(sample_time,'YYYYMMDDHH24MI') || TO_CHAR(TRUNC(TO_NUMBER(TO_CHAR(sample_time,'SS'))/30))
            ) co_base_qry
          ON time_window.start_time=co_base_qry.sample_yyyymmddhhmi30s
       )
  );

Modified source query

We will use the query defined in the part XXIV as a starting point. We will modify the source query as follow:

        SELECT BEGIN_TIME,
               C_EVENT0,
               C_EVENT1,
               C_EVENT2,
               C_EVENT3,
               C_EVENT4,
               C_EVENT5,
               C_EVENT6,
               C_EVENT7,
               C_EVENT8,
               C_EVENT9,
               C_EVENT10,
               C_EVENT11,
               C_EVENT12,
               SESSION_ID,
               EVENT_NAME0,
               EVENT_NAME1,
               EVENT_NAME2,
               EVENT_NAME3,
               EVENT_NAME4,
               EVENT_NAME5,
               EVENT_NAME6,
               EVENT_NAME7,
               EVENT_NAME8,
               EVENT_NAME9,
               EVENT_NAME10,
               EVENT_NAME11,
               EVENT_NAME12,
               MAX_EVENT
        FROM v$session_activity30s_lss
        ORDER BY sample_yyyymmddhhmi30s

XSLT processing

We will use the query defined in the part XXIV as a starting point with the following modifications:

  • We will only display the EVENT_NAMEyy legends that are meaningful e.g. not NULL. In order to do that we will add “choose” elements,
  • A vertical line and a time label are now displayed every 10 positions.

XSLT variables

We will add twelve additional variables in the XSLT document:

  • <xsl:variable name="event_name0"><xsl:value-of select="/descendant::EVENT_NAME0[position()=1]"/></xsl:variable>

    Event name 0,

  • <xsl:variable name="event_name12"><xsl:value-of select="/descendant::EVENT_NAME12[position()=1]"/></xsl:variable>

    Event name 12.

Furthermore:

  • The variable “bar_width” is set to 5.

Modified query

SET LINESIZE      4000
SET LONGCHUNKSIZE 60000
SET LONG          60000

SET FEEDBACK OFF
SET VERIFY   OFF
SET PAGESIZE 0

SET HEADING OFF

SPOOL generate_svg_25e.svg

SELECT XMLTRANSFORM
   (DBMS_XMLGEN.GETXMLTYPE
      ('SELECT BEGIN_TIME,
               C_EVENT0,
               C_EVENT1,
               C_EVENT2,
               C_EVENT3,
               C_EVENT4,
               C_EVENT5,
               C_EVENT6,
               C_EVENT7,
               C_EVENT8,
               C_EVENT9,
               C_EVENT10,
               C_EVENT11,
               C_EVENT12,
               SESSION_ID,
               EVENT_NAME0,
               EVENT_NAME1,
               EVENT_NAME2,
               EVENT_NAME3,
               EVENT_NAME4,
               EVENT_NAME5,
               EVENT_NAME6,
               EVENT_NAME7,
               EVENT_NAME8,
               EVENT_NAME9,
               EVENT_NAME10,
               EVENT_NAME11,
               EVENT_NAME12,
               MAX_EVENT
        FROM v$session_activity30s_lss
        ORDER BY sample_yyyymmddhhmi30s')
,      XMLTYPE.CREATEXML
   (TO_CLOB(
    '<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     <xsl:variable name="margin_top">20</xsl:variable>
     <xsl:variable name="margin_bottom">30</xsl:variable>
     <xsl:variable name="margin_left">40</xsl:variable>
     <xsl:variable name="margin_right">160</xsl:variable>
     <xsl:variable name="bar_width">5</xsl:variable>
     <xsl:variable name="graph_width"><xsl:value-of select="600+$margin_left+$margin_right"/></xsl:variable>
     <xsl:variable name="graph_height"><xsl:value-of select="100+$margin_top+$margin_bottom"/></xsl:variable>
     <xsl:variable name="graph_name">LSS Session Activity : </xsl:variable>
     <xsl:variable name="graph_unit">% Activity</xsl:variable>
     <xsl:variable name="yval_max"><xsl:value-of select="/descendant::MAX_EVENT[position()=1]"/></xsl:variable>
     <xsl:variable name="yval_min">0</xsl:variable>
     <xsl:variable name="var_mult"><xsl:value-of select="100 div (($yval_min)-($yval_max))"/></xsl:variable>
     <xsl:variable name="var_beg"><xsl:value-of select="($graph_height)-($margin_bottom)"/></xsl:variable>
     <xsl:variable name="sid"><xsl:value-of select="/descendant::SESSION_ID[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name0"><xsl:value-of select="/descendant::EVENT_NAME0[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name1"><xsl:value-of select="/descendant::EVENT_NAME1[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name2"><xsl:value-of select="/descendant::EVENT_NAME2[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name3"><xsl:value-of select="/descendant::EVENT_NAME3[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name4"><xsl:value-of select="/descendant::EVENT_NAME4[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name5"><xsl:value-of select="/descendant::EVENT_NAME5[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name6"><xsl:value-of select="/descendant::EVENT_NAME6[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name7"><xsl:value-of select="/descendant::EVENT_NAME7[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name8"><xsl:value-of select="/descendant::EVENT_NAME8[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name9"><xsl:value-of select="/descendant::EVENT_NAME9[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name10"><xsl:value-of select="/descendant::EVENT_NAME10[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name11"><xsl:value-of select="/descendant::EVENT_NAME11[position()=1]"/></xsl:variable>
     <xsl:variable name="event_name12"><xsl:value-of select="/descendant::EVENT_NAME12[position()=1]"/></xsl:variable>
       <xsl:template match="/">'
           )
    || 
    TO_CLOB(
         '<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" width="{$graph_width}" height="{$graph_height}">
           <text x="{$margin_left+1}" y="{($margin_top)-5}" style="fill: #000000; stroke: none;font-size:10px;text-anchor=start"><xsl:value-of select="concat($graph_name,$sid)"/></text>
           <text x="{($margin_bottom)-($graph_height)}" y="10" transform="rotate(-90)" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$graph_unit"/></text>
           <line x1="{($margin_left)-5}" y1="{($var_beg)-0}"   x2="{($graph_width)-($margin_right)+5}" y2="{($var_beg)-0}"  style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($var_beg)-25}"  x2="{($graph_width)-($margin_right)+5}" y2="{($var_beg)-25}" style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($var_beg)-50}"  x2="{($graph_width)-($margin_right)+5}" y2="{($var_beg)-50}" style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($var_beg)-75}"  x2="{($graph_width)-($margin_right)+5}" y2="{($var_beg)-75}" style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($var_beg)-100}" x2="{($graph_width)-($margin_right)+5}" y2="{($var_beg)-100}" style="stroke:lightblue;stroke-width:1" />
           <text x="{($margin_left)-24}" y="{($var_beg)-2}"   style="fill: #000000; stroke: none;font-size:8px;text-anchor=start">0</text>
           <text x="{($margin_left)-24}" y="{($var_beg)-25}"  style="fill: #000000; stroke: none;font-size:8px;text-anchor=start">25</text>
           <text x="{($margin_left)-24}" y="{($var_beg)-50}"  style="fill: #000000; stroke: none;font-size:8px;text-anchor=start">50</text>
           <text x="{($margin_left)-24}" y="{($var_beg)-75}"  style="fill: #000000; stroke: none;font-size:8px;text-anchor=start">75</text>
           <text x="{($margin_left)-24}" y="{($var_beg)-100}" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start">100</text>
           <line x1="{$margin_left}" y1="{($var_beg)}" x2="{$margin_left}" y2="{($var_beg)-100}" style="stroke:lightblue;stroke-width:1" />'
           )
    || 
    TO_CLOB(
          '<xsl:for-each select="ROWSET/ROW/BEGIN_TIME">
             <xsl:choose>
               <xsl:when test="(position()-1) mod 10=0">
                 <text x="{($margin_left)-9+($bar_width*(position()-1))}" y="{($var_beg)+12}" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="self::node()"/></text>
                 <line x1="{($margin_left)+($bar_width*(position()-1))}" y1="{($var_beg)+4}" x2="{($margin_left)+($bar_width*(position()-1))}" y2="{($var_beg)-100}" style="stroke:lightblue;stroke-width:1" /> 
               </xsl:when>
               <xsl:otherwise>
                 <line x1="{($margin_left)+($bar_width*(position()-1))}" y1="{($var_beg)+3}" x2="{($margin_left)+($bar_width*(position()-1))}" y2="{($var_beg)+0}" style="stroke:lightblue;stroke-width:1" /> 
               </xsl:otherwise>
             </xsl:choose>    
           </xsl:for-each>
           <xsl:variable name="v_path0">
             <xsl:for-each select="ROWSET/ROW/C_EVENT0">
               <xsl:variable name="x_val0">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val0">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val0,'','',$y_val0,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path0} {$x_val0},{($var_beg)} {$margin_left},{($var_beg)}" style="fill:limegreen;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path1">
             <xsl:for-each select="ROWSET/ROW/C_EVENT1">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val1">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val1">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val1,'','',$y_val1,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path0}{$v_path1}" style="fill:hotpink;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path2">
             <xsl:for-each select="ROWSET/ROW/C_EVENT2">
               <xsl:variable name="x_val2">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val2">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val2,'','',$y_val2,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path1}{$v_path2}" style="fill:indianred;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path3">
             <xsl:for-each select="ROWSET/ROW/C_EVENT3">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val3">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val3">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val3,'','',$y_val3,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path2}{$v_path3}" style="fill:olive;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path4">
             <xsl:for-each select="ROWSET/ROW/C_EVENT4">
               <xsl:variable name="x_val4">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val4">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val4,'','',$y_val4,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path3}{$v_path4}" style="fill:gray;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path5">
             <xsl:for-each select="ROWSET/ROW/C_EVENT5">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val5">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val5">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val5,'','',$y_val5,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path4}{$v_path5}" style="fill:sienna;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path6">
             <xsl:for-each select="ROWSET/ROW/C_EVENT6">
               <xsl:variable name="x_val6">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val6">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val6,'','',$y_val6,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path5}{$v_path6}" style="fill:orange;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path7">
             <xsl:for-each select="ROWSET/ROW/C_EVENT7">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val7">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val7">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val7,'','',$y_val7,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path6}{$v_path7}" style="fill:tan;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path8">
             <xsl:for-each select="ROWSET/ROW/C_EVENT8">
               <xsl:variable name="x_val8">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val8">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val8,'','',$y_val8,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path7}{$v_path8}" style="fill:royalblue;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path9">
             <xsl:for-each select="ROWSET/ROW/C_EVENT9">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val9">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val9">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val9,'','',$y_val9,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path8}{$v_path9}" style="fill:skyblue;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path10">
             <xsl:for-each select="ROWSET/ROW/C_EVENT10">
               <xsl:variable name="x_val10">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val10">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val10,'','',$y_val10,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path9}{$v_path10}" style="fill:lightcyan;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path11">
             <xsl:for-each select="ROWSET/ROW/C_EVENT11">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val11">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val11">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val11,'','',$y_val11,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path10}{$v_path11}" style="fill:lightgray;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path12">
             <xsl:for-each select="ROWSET/ROW/C_EVENT12">
               <xsl:variable name="x_val12">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val12">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val12,'','',$y_val12,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path11}{$v_path12}" style="fill:bisque;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:choose>
             <xsl:when test="string-length($event_name0)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+5}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name0"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+0}" width="{10}" height="{6}" fill="limegreen" stroke="black"/> 
             </xsl:when>
           </xsl:choose> 
           <xsl:choose>
             <xsl:when test="string-length($event_name1)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+13}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name1"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+8}" width="{10}" height="{6}" fill="hotpink" stroke="black"/> 
             </xsl:when>
           </xsl:choose> 
           <xsl:choose>
             <xsl:when test="string-length($event_name2)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+21}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name2"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+16}" width="{10}" height="{6}" fill="indianred" stroke="black"/> 
             </xsl:when>
           </xsl:choose> 
           <xsl:choose>
             <xsl:when test="string-length($event_name3)&gt;0">  
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+29}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name3"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+24}" width="{10}" height="{6}" fill="olive" stroke="black"/> 
             </xsl:when>
           </xsl:choose>  
           <xsl:choose>
             <xsl:when test="string-length($event_name4)&gt;0"> 
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+37}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name4"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+32}" width="{10}" height="{6}" fill="gray" stroke="black"/> 
             </xsl:when>
           </xsl:choose> 
           <xsl:choose>
             <xsl:when test="string-length($event_name5)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+45}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name5"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+40}" width="{10}" height="{6}" fill="sienna" stroke="black"/>
             </xsl:when>
           </xsl:choose>'
           ) 
    || 
    TO_CLOB(
          '<xsl:choose>
             <xsl:when test="string-length($event_name6)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+53}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name6"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+48}" width="{10}" height="{6}" fill="orange" stroke="black"/> 
             </xsl:when>
           </xsl:choose> 
           <xsl:choose>
             <xsl:when test="string-length($event_name7)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+61}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name7"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+56}" width="{10}" height="{6}" fill="tan" stroke="black"/>  
             </xsl:when>
           </xsl:choose>
           <xsl:choose>
             <xsl:when test="string-length($event_name8)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+69}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name8"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+64}" width="{10}" height="{6}" fill="royalblue" stroke="black"/> 
             </xsl:when>
           </xsl:choose> 
           <xsl:choose>
             <xsl:when test="string-length($event_name9)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+77}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name9"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+72}" width="{10}" height="{6}" fill="skyblue" stroke="black"/>
             </xsl:when>
           </xsl:choose> 
           <xsl:choose>
             <xsl:when test="string-length($event_name10)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+85}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name10"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+80}" width="{10}" height="{6}" fill="lightcyan" stroke="black"/> 
             </xsl:when>
           </xsl:choose> 
           <xsl:choose>
             <xsl:when test="string-length($event_name11)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+93}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name11"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+88}" width="{10}" height="{6}" fill="lightgray" stroke="black"/> 
             </xsl:when>
           </xsl:choose>  
           <xsl:choose>
             <xsl:when test="string-length($event_name12)&gt;0">
               <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+101}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$event_name12"/></text>
               <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+96}" width="{10}" height="{6}" fill="bisque" stroke="black"/>
             </xsl:when>
           </xsl:choose>   
         </svg>
       </xsl:template>
     </xsl:stylesheet>'
           )
   )
   ) 
FROM dual;

SPOOL OFF
SET HEADING ON

SET VERIFY   ON
SET FEEDBACK ON

Result:

generate_svg_25e

Remarks:

  • The query has been executed from the CDB$ROOT container by the C##LSS common user,
  • The view v$session_activity30s_lss has been created from the CDB$ROOT container in the C##LSS schema,
  • The system variables LINESIZE and LONGCHUNKSIZE have been increased to 4000 and 60000 respectively,
  • The LSS sampling period interval is set to 2 seconds.

Generating SVG graphics with SQL*Plus – Part XXIV – Stacked area graph – Session Activity – Light Sampling Sessions

Scope

In the previous post we have displayed the top 20 activity sessions. It could be interesting to know how much a session is waiting on such or such event or is using the cpu. We will change the sampling period interval to 2 seconds.
We will create a view in order to display the session activity and we will use a function to get the session id.

Function get_current_session

This function will return the session id that we want to analyse. Basically you could store the session id in a table and retrieve it with this function. You will find a example below:

CREATE OR REPLACE FUNCTION get_current_session RETURN NUMBER 
AS 
   v_param_value lss$parameter.parameter_value%TYPE;
BEGIN

   SELECT parameter_value
   INTO v_param_value
   FROM LSS$parameter
   WHERE parameter_name = 'current_session';
   
   RETURN TO_NUMBER(v_param_value);
   
   EXCEPTION
      WHEN TOO_MANY_ROWS THEN
         RETURN -1;
      WHEN NO_DATA_FOUND THEN
         RETURN -1;
      WHEN OTHERS THEN
         RAISE;
         
END get_current_session;

View creation – Step 1

The starting point of this view will be v$aas_light_sampling_sessions.
The query name session_events gives the top 12 event activities linked to the wait events of a session (excluded the cpu activity) as follow:

WITH session_events AS
   (
   SELECT event,
          COUNT(*) count_event, 
          RANK() OVER (ORDER BY COUNT(*) DESC, EVENT) rank_event 
   FROM lss$_sampling_session
   WHERE SID = get_current_session
     AND sample_time >= SYSDATE -(1/24) 
     AND session_state <> 'C'
   GROUP BY event
   ORDER BY count_event DESC
   FETCH FIRST 12 ROWS ONLY
   )

View creation – Step 2

Every minute we will count the number of events that are linked to a wait class or a cpu event for the target session as follow:

            SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') sample_yyyymmddhhmi,
                   MAX(sample_id) - MIN(sample_id) nb_samples,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),-1,1)) count_event0,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,1))  count_event1,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,1))  count_event2,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,1))  count_event3,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,1))  count_event4,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,1))  count_event5,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,1))  count_event6,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,1))  count_event7,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,1))  count_event8,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,1))  count_event9,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,1)) count_event10,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,1)) count_event11,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,1)) count_event12,
                   'cpu'    event_name0,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,sess_event.event))  event_name1,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,sess_event.event))  event_name2,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,sess_event.event))  event_name3,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,sess_event.event))  event_name4,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,sess_event.event))  event_name5,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,sess_event.event))  event_name6,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,sess_event.event))  event_name7,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,sess_event.event))  event_name8,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,sess_event.event))  event_name9,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,sess_event.event)) event_name10,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,sess_event.event)) event_name11,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,sess_event.event)) event_name12
            FROM lss$_sampling_session lss
            LEFT OUTER JOIN session_events sess_event
              ON sess_event.event = lss.event
            WHERE lss.sid = get_current_session
            GROUP BY TO_CHAR(sample_time,'YYYYMMDDHH24MI')

We will also store the different event names.

View creation – Step 3

In the LSS sampling process, it might happen that a specific period of time does not contain any data e.g. LSS process is not working during this period. We will handle this sampling process inactivity during the last hour as follow:

        SELECT NVL(co_base_qry.sample_yyyymmddhhmi,time_window.start_time) sample_yyyymmddhhmi,
               NVL(co_base_qry.nb_samples,1)    nb_samples,
               NVL(co_base_qry.count_event0,0)  count_event0,
               NVL(co_base_qry.count_event1,0)  count_event1,
               NVL(co_base_qry.count_event2,0)  count_event2,
               NVL(co_base_qry.count_event3,0)  count_event3,
               NVL(co_base_qry.count_event4,0)  count_event4,
               NVL(co_base_qry.count_event5,0)  count_event5,
               NVL(co_base_qry.count_event6,0)  count_event6,
               NVL(co_base_qry.count_event7,0)  count_event7,
               NVL(co_base_qry.count_event8,0)  count_event8,
               NVL(co_base_qry.count_event9,0)  count_event9,
               NVL(co_base_qry.count_event10,0) count_event10,
               NVL(co_base_qry.count_event11,0) count_event11,
               NVL(co_base_qry.count_event12,0) count_event12,
               co_base_qry.event_name0,
               co_base_qry.event_name1,
               co_base_qry.event_name2,
               co_base_qry.event_name3,
               co_base_qry.event_name4,
               co_base_qry.event_name5,
               co_base_qry.event_name6,
               co_base_qry.event_name7,
               co_base_qry.event_name8,
               co_base_qry.event_name9,
               co_base_qry.event_name10,
               co_base_qry.event_name11,
               co_base_qry.event_name12
        FROM
           (SELECT TO_CHAR(SYSDATE - (LEVEL/24/60),'YYYYMMDDHH24MI') start_time
            FROM DUAL 
            CONNECT BY LEVEL <= 61
            ) time_window
        LEFT OUTER JOIN 
           (SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') sample_yyyymmddhhmi,
                   MAX(sample_id) - MIN(sample_id) nb_samples,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),-1,1)) count_event0,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,1))  count_event1,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,1))  count_event2,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,1))  count_event3,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,1))  count_event4,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,1))  count_event5,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,1))  count_event6,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,1))  count_event7,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,1))  count_event8,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,1))  count_event9,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,1)) count_event10,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,1)) count_event11,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,1)) count_event12,
                   'cpu'    event_name0,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,sess_event.event))  event_name1,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,sess_event.event))  event_name2,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,sess_event.event))  event_name3,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,sess_event.event))  event_name4,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,sess_event.event))  event_name5,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,sess_event.event))  event_name6,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,sess_event.event))  event_name7,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,sess_event.event))  event_name8,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,sess_event.event))  event_name9,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,sess_event.event)) event_name10,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,sess_event.event)) event_name11,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,sess_event.event)) event_name12
            FROM lss$_sampling_session lss
            LEFT OUTER JOIN session_events sess_event
              ON sess_event.event = lss.event
            WHERE lss.sid = get_current_session
            GROUP BY TO_CHAR(sample_time,'YYYYMMDDHH24MI')
            ) co_base_qry
          ON time_window.start_time=co_base_qry.sample_yyyymmddhhmi

View creation – Step 4

To define how many events in average that are linked to the target session, we will count the top 12 wait events plus the cpu event on a period of time of one minute and we will divide by the number of samples plus one as follow:

    SELECT sample_yyyymmddhhmi,
           TRUNC((count_event0/(nb_samples+1)),3)  avge1,  
           TRUNC((count_event1/(nb_samples+1)),3)  avge2,  
           TRUNC((count_event2/(nb_samples+1)),3)  avge3, 
           TRUNC((count_event3/(nb_samples+1)),3)  avge4,  
           TRUNC((count_event4/(nb_samples+1)),3)  avge5,  
           TRUNC((count_event5/(nb_samples+1)),3)  avge6,  
           TRUNC((count_event6/(nb_samples+1)),3)  avge7,  
           TRUNC((count_event7/(nb_samples+1)),3)  avge8,  
           TRUNC((count_event8/(nb_samples+1)),3)  avge9,  
           TRUNC((count_event9/(nb_samples+1)),3)  avge10, 
           TRUNC((count_event10/(nb_samples+1)),3) avge11, 
           TRUNC((count_event11/(nb_samples+1)),3) avge12, 
           TRUNC((count_event12/(nb_samples+1)),3) avge13,  
           event_name0,
           event_name1,
           event_name2,
           event_name3,
           event_name4,
           event_name5,
           event_name6,
           event_name7,
           event_name8,
           event_name9,
           event_name10,
           event_name11,
           event_name12
    FROM 
       (SELECT NVL(co_base_qry.sample_yyyymmddhhmi,time_window.start_time) sample_yyyymmddhhmi,
               NVL(co_base_qry.nb_samples,1)    nb_samples,
               NVL(co_base_qry.count_event0,0)  count_event0,
               NVL(co_base_qry.count_event1,0)  count_event1,
               NVL(co_base_qry.count_event2,0)  count_event2,
               NVL(co_base_qry.count_event3,0)  count_event3,
               NVL(co_base_qry.count_event4,0)  count_event4,
               NVL(co_base_qry.count_event5,0)  count_event5,
               NVL(co_base_qry.count_event6,0)  count_event6,
               NVL(co_base_qry.count_event7,0)  count_event7,
               NVL(co_base_qry.count_event8,0)  count_event8,
               NVL(co_base_qry.count_event9,0)  count_event9,
               NVL(co_base_qry.count_event10,0) count_event10,
               NVL(co_base_qry.count_event11,0) count_event11,
               NVL(co_base_qry.count_event12,0) count_event12,
               co_base_qry.event_name0,
               co_base_qry.event_name1,
               co_base_qry.event_name2,
               co_base_qry.event_name3,
               co_base_qry.event_name4,
               co_base_qry.event_name5,
               co_base_qry.event_name6,
               co_base_qry.event_name7,
               co_base_qry.event_name8,
               co_base_qry.event_name9,
               co_base_qry.event_name10,
               co_base_qry.event_name11,
               co_base_qry.event_name12
        FROM
           (SELECT TO_CHAR(SYSDATE - (LEVEL/24/60),'YYYYMMDDHH24MI') start_time
            FROM DUAL 
            CONNECT BY LEVEL <= 61
            ) time_window
        LEFT OUTER JOIN 
           (SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') sample_yyyymmddhhmi,
                   MAX(sample_id) - MIN(sample_id) nb_samples,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),-1,1)) count_event0,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,1))  count_event1,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,1))  count_event2,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,1))  count_event3,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,1))  count_event4,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,1))  count_event5,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,1))  count_event6,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,1))  count_event7,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,1))  count_event8,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,1))  count_event9,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,1)) count_event10,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,1)) count_event11,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,1)) count_event12,
                   'cpu'    event_name0,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,sess_event.event))  event_name1,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,sess_event.event))  event_name2,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,sess_event.event))  event_name3,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,sess_event.event))  event_name4,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,sess_event.event))  event_name5,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,sess_event.event))  event_name6,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,sess_event.event))  event_name7,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,sess_event.event))  event_name8,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,sess_event.event))  event_name9,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,sess_event.event)) event_name10,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,sess_event.event)) event_name11,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,sess_event.event)) event_name12
            FROM lss$_sampling_session lss
            LEFT OUTER JOIN session_events sess_event
              ON sess_event.event = lss.event
            WHERE lss.sid = get_current_session
            GROUP BY TO_CHAR(sample_time,'YYYYMMDDHH24MI')
            ) co_base_qry
          ON time_window.start_time=co_base_qry.sample_yyyymmddhhmi
       )

View creation – Step 5

Finally we will accumulate the different events AVGE from the EVENT0 to EVENT12 event as follow:

CREATE OR REPLACE VIEW v$session_activity_lss
AS
WITH session_events AS
   (
   SELECT event,
          COUNT(*) count_event, 
          RANK() OVER (ORDER BY COUNT(*) DESC, EVENT) rank_event 
   FROM lss$_sampling_session
   WHERE SID = get_current_session
     AND sample_time >= SYSDATE -(1/24) 
     AND session_state <> 'C'
   GROUP BY event
   ORDER BY count_event DESC
   FETCH FIRST 12 ROWS ONLY
   )
SELECT sample_yyyymmddhhmi,
       SUBSTR(sample_yyyymmddhhmi,9,2) || ':' || SUBSTR(sample_yyyymmddhhmi,11,2) BEGIN_TIME,
       avge1                                                                             C_EVENT0,
       avge1+avge2                                                                       C_EVENT1,
       avge1+avge2+avge3                                                                 C_EVENT2,
       avge1+avge2+avge3+avge4                                                           C_EVENT3,
       avge1+avge2+avge3+avge4+avge5                                                     C_EVENT4,
       avge1+avge2+avge3+avge4+avge5+avge6                                               C_EVENT5,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7                                         C_EVENT6,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8                                   C_EVENT7,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9                             C_EVENT8,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10                      C_EVENT9,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11               C_EVENT10,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11+avge12        C_EVENT11,
       avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11+avge12+avge13 C_EVENT12,
       MAX(CEIL(avge1+avge2+avge3+avge4+avge5+avge6+avge7+avge8+avge9+avge10+avge11+avge12+avge13)) OVER() MAX_EVENT,
       (SELECT get_current_session FROM DUAL) session_id,
       MAX(event_name0)  OVER() EVENT_NAME0,
       MAX(event_name1)  OVER() EVENT_NAME1,
       MAX(event_name2)  OVER() EVENT_NAME2,
       MAX(event_name3)  OVER() EVENT_NAME3,
       MAX(event_name4)  OVER() EVENT_NAME4,
       MAX(event_name5)  OVER() EVENT_NAME5,
       MAX(event_name6)  OVER() EVENT_NAME6,
       MAX(event_name7)  OVER() EVENT_NAME7,
       MAX(event_name8)  OVER() EVENT_NAME8,
       MAX(event_name9)  OVER() EVENT_NAME9,
       MAX(event_name10) OVER() EVENT_NAME10,
       MAX(event_name11) OVER() EVENT_NAME11,
       MAX(event_name12) OVER() EVENT_NAME12
FROM
   (SELECT sample_yyyymmddhhmi,
           TRUNC((count_event0/(nb_samples+1)),3)  avge1,  
           TRUNC((count_event1/(nb_samples+1)),3)  avge2,  
           TRUNC((count_event2/(nb_samples+1)),3)  avge3, 
           TRUNC((count_event3/(nb_samples+1)),3)  avge4,  
           TRUNC((count_event4/(nb_samples+1)),3)  avge5,  
           TRUNC((count_event5/(nb_samples+1)),3)  avge6,  
           TRUNC((count_event6/(nb_samples+1)),3)  avge7,  
           TRUNC((count_event7/(nb_samples+1)),3)  avge8,  
           TRUNC((count_event8/(nb_samples+1)),3)  avge9,  
           TRUNC((count_event9/(nb_samples+1)),3)  avge10, 
           TRUNC((count_event10/(nb_samples+1)),3) avge11, 
           TRUNC((count_event11/(nb_samples+1)),3) avge12, 
           TRUNC((count_event12/(nb_samples+1)),3) avge13,  
           event_name0,
           event_name1,
           event_name2,
           event_name3,
           event_name4,
           event_name5,
           event_name6,
           event_name7,
           event_name8,
           event_name9,
           event_name10,
           event_name11,
           event_name12
    FROM 
       (SELECT NVL(co_base_qry.sample_yyyymmddhhmi,time_window.start_time) sample_yyyymmddhhmi,
               NVL(co_base_qry.nb_samples,1)    nb_samples,
               NVL(co_base_qry.count_event0,0)  count_event0,
               NVL(co_base_qry.count_event1,0)  count_event1,
               NVL(co_base_qry.count_event2,0)  count_event2,
               NVL(co_base_qry.count_event3,0)  count_event3,
               NVL(co_base_qry.count_event4,0)  count_event4,
               NVL(co_base_qry.count_event5,0)  count_event5,
               NVL(co_base_qry.count_event6,0)  count_event6,
               NVL(co_base_qry.count_event7,0)  count_event7,
               NVL(co_base_qry.count_event8,0)  count_event8,
               NVL(co_base_qry.count_event9,0)  count_event9,
               NVL(co_base_qry.count_event10,0) count_event10,
               NVL(co_base_qry.count_event11,0) count_event11,
               NVL(co_base_qry.count_event12,0) count_event12,
               co_base_qry.event_name0,
               co_base_qry.event_name1,
               co_base_qry.event_name2,
               co_base_qry.event_name3,
               co_base_qry.event_name4,
               co_base_qry.event_name5,
               co_base_qry.event_name6,
               co_base_qry.event_name7,
               co_base_qry.event_name8,
               co_base_qry.event_name9,
               co_base_qry.event_name10,
               co_base_qry.event_name11,
               co_base_qry.event_name12
        FROM
           (SELECT TO_CHAR(SYSDATE - (LEVEL/24/60),'YYYYMMDDHH24MI') start_time
            FROM DUAL 
            CONNECT BY LEVEL <= 61
            ) time_window
        LEFT OUTER JOIN 
           (SELECT TO_CHAR(sample_time,'YYYYMMDDHH24MI') sample_yyyymmddhhmi,
                   MAX(sample_id) - MIN(sample_id) nb_samples,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),-1,1)) count_event0,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,1))  count_event1,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,1))  count_event2,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,1))  count_event3,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,1))  count_event4,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,1))  count_event5,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,1))  count_event6,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,1))  count_event7,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,1))  count_event8,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,1))  count_event9,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,1)) count_event10,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,1)) count_event11,
                   COUNT(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,1)) count_event12,
                   'cpu'    event_name0,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),1,sess_event.event))  event_name1,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),2,sess_event.event))  event_name2,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),3,sess_event.event))  event_name3,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),4,sess_event.event))  event_name4,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),5,sess_event.event))  event_name5,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),6,sess_event.event))  event_name6,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),7,sess_event.event))  event_name7,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),8,sess_event.event))  event_name8,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),9,sess_event.event))  event_name9,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),10,sess_event.event)) event_name10,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),11,sess_event.event)) event_name11,
                   MAX(DECODE(DECODE(session_state,'C',-1,sess_event.rank_event),12,sess_event.event)) event_name12
            FROM lss$_sampling_session lss
            LEFT OUTER JOIN session_events sess_event
              ON sess_event.event = lss.event
            WHERE lss.sid = get_current_session
            GROUP BY TO_CHAR(sample_time,'YYYYMMDDHH24MI')
            ) co_base_qry
          ON time_window.start_time=co_base_qry.sample_yyyymmddhhmi
       )
  );

Modified source query

We will modify the source query as follow:

        SELECT BEGIN_TIME,
               C_EVENT0,
               C_EVENT1,
               C_EVENT2,
               C_EVENT3,
               C_EVENT4,
               C_EVENT5,
               C_EVENT6,
               C_EVENT7,
               C_EVENT8,
               C_EVENT9,
               C_EVENT10,
               C_EVENT11,
               C_EVENT12,
               SESSION_ID,
               EVENT_NAME0,
               EVENT_NAME1,
               EVENT_NAME2,
               EVENT_NAME3,
               EVENT_NAME4,
               EVENT_NAME5,
               EVENT_NAME6,
               EVENT_NAME7,
               EVENT_NAME8,
               EVENT_NAME9,
               EVENT_NAME10,
               EVENT_NAME11,
               EVENT_NAME12,
               MAX_EVENT
        FROM v$session_activity_lss
        ORDER BY sample_yyyymmddhhmi

XSLT processing

We will use the query defined in the part XXI as a starting point with the following modifications:

  • The differents “for-each” “ROWSET/ROW/C_CPU” to “ROWSET/ROW/C_CLUSTER” have been replaced by “ROWSET/ROW/C_EVENT0” to “ROWSET/ROW/C_EVENT12”,
  • Utilization of two variables “var_mult” and “var_beg” to simplify formulas.

XSLT variables

We will add three additional variables in the XSLT document:

  • <xsl:variable name="var_mult"><xsl:value-of select="100 div (($yval_min)-($yval_max))"/></xsl:variable>

    Variable used to simplify several formulas,

  • <xsl:variable name="var_beg"><xsl:value-of select="($graph_height)-($margin_bottom)"/></xsl:variable>

    Variable also used to simplify several formulas,

  • <xsl:variable name="sid"><xsl:value-of select="/descendant::SESSION_ID[position()=1]"/></xsl:variable>

    Target session id.

Furthermore:

  • The variable “margin_rigth” is set to 160,
  • The variable “graph_name” is set to ‘LSS Session Activity : ‘,
  • The variable “yval_max” is set to the first value of the column MAX_EVENT.

Modified query

SET LINESIZE      2000
SET LONGCHUNKSIZE 30000
SET LONG          30000

SET FEEDBACK OFF
SET VERIFY   OFF
SET PAGESIZE 0

SET HEADING OFF

SPOOL generate_svg_24d.svg

SELECT XMLTRANSFORM
   (DBMS_XMLGEN.GETXMLTYPE
      ('SELECT BEGIN_TIME,
               C_EVENT0,
               C_EVENT1,
               C_EVENT2,
               C_EVENT3,
               C_EVENT4,
               C_EVENT5,
               C_EVENT6,
               C_EVENT7,
               C_EVENT8,
               C_EVENT9,
               C_EVENT10,
               C_EVENT11,
               C_EVENT12,
               SESSION_ID,
               EVENT_NAME0,
               EVENT_NAME1,
               EVENT_NAME2,
               EVENT_NAME3,
               EVENT_NAME4,
               EVENT_NAME5,
               EVENT_NAME6,
               EVENT_NAME7,
               EVENT_NAME8,
               EVENT_NAME9,
               EVENT_NAME10,
               EVENT_NAME11,
               EVENT_NAME12,
               MAX_EVENT
        FROM v$session_activity_lss
        ORDER BY sample_yyyymmddhhmi')
,      XMLTYPE.CREATEXML
   (TO_CLOB(
    '<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     <xsl:variable name="margin_top">20</xsl:variable>
     <xsl:variable name="margin_bottom">30</xsl:variable>
     <xsl:variable name="margin_left">40</xsl:variable>
     <xsl:variable name="margin_right">160</xsl:variable>
     <xsl:variable name="bar_width">10</xsl:variable>
     <xsl:variable name="graph_width"><xsl:value-of select="600+$margin_left+$margin_right"/></xsl:variable>
     <xsl:variable name="graph_height"><xsl:value-of select="100+$margin_top+$margin_bottom"/></xsl:variable>
     <xsl:variable name="graph_name">LSS Session Activity : </xsl:variable>
     <xsl:variable name="graph_unit">% Activity</xsl:variable>
     <xsl:variable name="yval_max"><xsl:value-of select="/descendant::MAX_EVENT[position()=1]"/></xsl:variable>
     <xsl:variable name="yval_min">0</xsl:variable>
     <xsl:variable name="var_mult"><xsl:value-of select="100 div (($yval_min)-($yval_max))"/></xsl:variable>
     <xsl:variable name="var_beg"><xsl:value-of select="($graph_height)-($margin_bottom)"/></xsl:variable>
     <xsl:variable name="sid"><xsl:value-of select="/descendant::SESSION_ID[position()=1]"/></xsl:variable>
       <xsl:template match="/">'
           )
    || 
    TO_CLOB(
         '<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" width="{$graph_width}" height="{$graph_height}">
           <text x="{$margin_left+1}" y="{($margin_top)-5}" style="fill: #000000; stroke: none;font-size:10px;text-anchor=start"><xsl:value-of select="concat($graph_name,$sid)"/></text>
           <text x="{($margin_bottom)-($graph_height)}" y="10" transform="rotate(-90)" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="$graph_unit"/></text>
           <line x1="{($margin_left)-5}" y1="{($var_beg)-0}"   x2="{($graph_width)-($margin_right)+5}" y2="{($var_beg)-0}"  style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($var_beg)-25}"  x2="{($graph_width)-($margin_right)+5}" y2="{($var_beg)-25}" style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($var_beg)-50}"  x2="{($graph_width)-($margin_right)+5}" y2="{($var_beg)-50}" style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($var_beg)-75}"  x2="{($graph_width)-($margin_right)+5}" y2="{($var_beg)-75}" style="stroke:lightblue;stroke-width:1" />
           <line x1="{($margin_left)-5}" y1="{($var_beg)-100}" x2="{($graph_width)-($margin_right)+5}" y2="{($var_beg)-100}" style="stroke:lightblue;stroke-width:1" />
           <text x="{($margin_left)-24}" y="{($var_beg)-2}"   style="fill: #000000; stroke: none;font-size:8px;text-anchor=start">0</text>
           <text x="{($margin_left)-24}" y="{($var_beg)-25}"  style="fill: #000000; stroke: none;font-size:8px;text-anchor=start">25</text>
           <text x="{($margin_left)-24}" y="{($var_beg)-50}"  style="fill: #000000; stroke: none;font-size:8px;text-anchor=start">50</text>
           <text x="{($margin_left)-24}" y="{($var_beg)-75}"  style="fill: #000000; stroke: none;font-size:8px;text-anchor=start">75</text>
           <text x="{($margin_left)-24}" y="{($var_beg)-100}" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start">100</text>
           <line x1="{$margin_left}" y1="{($var_beg)}" x2="{$margin_left}" y2="{($var_beg)-100}" style="stroke:lightblue;stroke-width:1" />'
           )
    || 
    TO_CLOB(
          '<xsl:for-each select="ROWSET/ROW/BEGIN_TIME">
             <xsl:choose>
               <xsl:when test="(position()-1) mod 5=0">
                 <text x="{($margin_left)-9+($bar_width*(position()-1))}" y="{($var_beg)+12}" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="self::node()"/></text>
                 <line x1="{($margin_left)+($bar_width*(position()-1))}" y1="{($var_beg)+4}" x2="{($margin_left)+($bar_width*(position()-1))}" y2="{($var_beg)-100}" style="stroke:lightblue;stroke-width:1" /> 
               </xsl:when>
               <xsl:otherwise>
                 <line x1="{($margin_left)+($bar_width*(position()-1))}" y1="{($var_beg)+3}" x2="{($margin_left)+($bar_width*(position()-1))}" y2="{($var_beg)+0}" style="stroke:lightblue;stroke-width:1" /> 
               </xsl:otherwise>
             </xsl:choose>    
           </xsl:for-each>
           <xsl:variable name="v_path0">
             <xsl:for-each select="ROWSET/ROW/C_EVENT0">
               <xsl:variable name="x_val0">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val0">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val0,'','',$y_val0,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path0} {$x_val0},{($var_beg)} {$margin_left},{($var_beg)}" style="fill:limegreen;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path1">
             <xsl:for-each select="ROWSET/ROW/C_EVENT1">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val1">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val1">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val1,'','',$y_val1,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path0}{$v_path1}" style="fill:hotpink;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path2">
             <xsl:for-each select="ROWSET/ROW/C_EVENT2">
               <xsl:variable name="x_val2">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val2">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val2,'','',$y_val2,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path1}{$v_path2}" style="fill:indianred;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path3">
             <xsl:for-each select="ROWSET/ROW/C_EVENT3">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val3">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val3">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val3,'','',$y_val3,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path2}{$v_path3}" style="fill:olive;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path4">
             <xsl:for-each select="ROWSET/ROW/C_EVENT4">
               <xsl:variable name="x_val4">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val4">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val4,'','',$y_val4,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path3}{$v_path4}" style="fill:gray;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path5">
             <xsl:for-each select="ROWSET/ROW/C_EVENT5">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val5">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val5">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val5,'','',$y_val5,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path4}{$v_path5}" style="fill:sienna;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path6">
             <xsl:for-each select="ROWSET/ROW/C_EVENT6">
               <xsl:variable name="x_val6">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val6">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val6,'','',$y_val6,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path5}{$v_path6}" style="fill:orange;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path7">
             <xsl:for-each select="ROWSET/ROW/C_EVENT7">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val7">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val7">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val7,'','',$y_val7,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path6}{$v_path7}" style="fill:tan;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path8">
             <xsl:for-each select="ROWSET/ROW/C_EVENT8">
               <xsl:variable name="x_val8">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val8">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val8,'','',$y_val8,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path7}{$v_path8}" style="fill:royalblue;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path9">
             <xsl:for-each select="ROWSET/ROW/C_EVENT9">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val9">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val9">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val9,'','',$y_val9,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path8}{$v_path9}" style="fill:skyblue;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path10">
             <xsl:for-each select="ROWSET/ROW/C_EVENT10">
               <xsl:variable name="x_val10">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val10">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val10,'','',$y_val10,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path9}{$v_path10}" style="fill:lightcyan;stroke:none;stroke-width:1" />'
           )
   ||
   TO_CLOB(
          '<xsl:variable name="v_path11">
             <xsl:for-each select="ROWSET/ROW/C_EVENT11">
               <xsl:sort select="position()" order="descending" data-type="number"/>
               <xsl:variable name="x_val11">
                 <xsl:value-of select="$margin_left+$bar_width*(last()-position())"/>
               </xsl:variable>
               <xsl:variable name="y_val11">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val11,'','',$y_val11,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path10}{$v_path11}" style="fill:lightgray;stroke:none;stroke-width:1" />
           <xsl:variable name="v_path12">
             <xsl:for-each select="ROWSET/ROW/C_EVENT12">
               <xsl:variable name="x_val12">
                 <xsl:value-of select="$margin_left+$bar_width*(position()-1)"/>
               </xsl:variable>
               <xsl:variable name="y_val12">
                 <xsl:value-of select="round(($var_beg)-((($yval_min)-(self::node()))*($var_mult)))"/>
               </xsl:variable>
               <xsl:value-of select="concat($x_val12,'','',$y_val12,'' '')"/>
             </xsl:for-each>
           </xsl:variable>
           <polygon points="{$v_path11}{$v_path12}" style="fill:bisque;stroke:none;stroke-width:1" />
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+5}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME0[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+0}" width="{10}" height="{6}" fill="limegreen" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+13}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME1[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+8}" width="{10}" height="{6}" fill="hotpink" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+21}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME2[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+16}" width="{10}" height="{6}" fill="indianred" stroke="black"/>   
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+29}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME3[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+24}" width="{10}" height="{6}" fill="olive" stroke="black"/>   
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+37}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME4[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+32}" width="{10}" height="{6}" fill="gray" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+45}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME5[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+40}" width="{10}" height="{6}" fill="sienna" stroke="black"/>'
           ) 
    || 
    TO_CLOB(
          '<text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+53}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME6[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+48}" width="{10}" height="{6}" fill="orange" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+61}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME7[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+56}" width="{10}" height="{6}" fill="tan" stroke="black"/>  
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+69}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME8[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+64}" width="{10}" height="{6}" fill="royalblue" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+77}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME9[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+72}" width="{10}" height="{6}" fill="skyblue" stroke="black"/>
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+85}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME10[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+80}" width="{10}" height="{6}" fill="lightcyan" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+93}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME11[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+88}" width="{10}" height="{6}" fill="lightgray" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+101}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="/descendant::EVENT_NAME12[position()=1]"/></text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+96}" width="{10}" height="{6}" fill="bisque" stroke="black"/>   
         </svg>
       </xsl:template>
     </xsl:stylesheet>'
           )
   )
   ) 
FROM dual;

SPOOL OFF
SET HEADING ON

SET VERIFY   ON
SET FEEDBACK ON

Result:

generate_svg_24d

Remarks:

  • The query has been executed from the CDB$ROOT container by the C##LSS common user,
  • The v$session_activity_lss has been created from the CDB$ROOT container in the C##LSS schema,
  • The views defined in the part XXI to part XXIII could be modified in order to use v$active_session_history (ASH) if available and licensed,
  • The view v$session_activity_lss is a session id consolidation e.g. it might exist several sessions in different CDB/PDBs with the same session id.

Generating SVG graphics with SQL*Plus – Part XXIII – Horizontal stacked bar graph – Top Activity Sessions – Light Sampling Sessions – CDB database

Scope

It could be interesting to have the top activity sessions of a whole CDB database e.g. through all the CDB/PDB. We will limit to the top 20 activity sessions. For each session we will display:

  • Session Id,
  • Activity,
  • User Name,
  • Program Name,
  • Container Name.

Remark: The maximum value of the ‘Activity’ field is linked to the maximum activity session during the last 10 minutes interval.

We will create a view in order to display the top activity sessions.

View creation – Step 1

For the last 10 minutes, we will count the number of active sessions that are linked to a wait class or a cpu event as well as the total number of events per session id/serial# as follow:

        SELECT sid,
               serial#,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),-1,1)) count_cpu,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),0,1))  count_other,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),1,1))  count_application,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),2,1))  count_configuration,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),3,1))  count_administrative,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),4,1))  count_concurrency,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),5,1))  count_commit,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),7,1))  count_network,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),8,1))  count_user_io,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),9,1))  count_system_io,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),10,1)) count_scheduler,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),11,1)) count_cluster,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),12,1)) count_queueing,
               COUNT(*)                             count_total,
               MAX(lss_sample.nb_samples)           max_samples,
               MAX(user#)                           max_user#,
               MAX(program)                         max_program,
               MAX(con_id)                          max_con_id
        FROM lss$_sampling_session
        CROSS JOIN 
           (SELECT MAX(sample_id) - MIN(sample_id)  nb_samples
            FROM lss$_sampling_session
            WHERE sample_time >= SYSDATE -(10/24/60)
           ) lss_sample
        WHERE sample_time >= SYSDATE -(10/24/60)
        GROUP BY sid,
                 serial#
        ORDER BY count_total DESC
        FETCH FIRST 20 ROWS ONLY

Remarks:

  • The Cross Join query computes the number of samples during the last 10 minutes,
  • We have used the clause ‘FETCH FIRST 20 ROWS ONLY’ in order to have only the top 20.

View creation – Step 2

For the top 20 activity sessions, we will define for each session in average how much it is waiting on such or such wait class and how much it is using cpu as follow:

     SELECT sid,
           serial#,
           max_user#   user#,
           max_program user_program,
           max_con_id  user_con_id,
           TRUNC((count_cpu/(max_samples+1)),3)            aas1,  --aas_cpu
           TRUNC((count_other/(max_samples+1)),3)          aas2,  --aas_other
           TRUNC((count_application/(max_samples+1)),3)    aas3,  --aas_application
           TRUNC((count_configuration/(max_samples+1)),3)  aas4,  --aas_configuration
           TRUNC((count_administrative/(max_samples+1)),3) aas5,  --aas_administrative
           TRUNC((count_concurrency/(max_samples+1)),3)    aas6,  --aas_concurrency
           TRUNC((count_commit/(max_samples+1)),3)         aas7,  --aas_commit
           TRUNC((count_network/(max_samples+1)),3)        aas8,  --aas_network
           TRUNC((count_user_io/(max_samples+1)),3)        aas9,  --aas_user_io
           TRUNC((count_system_io/(max_samples+1)),3)      aas10, --aas_system_io
           TRUNC((count_scheduler/(max_samples+1)),3)      aas11, --aas_scheduler
           TRUNC((count_cluster/(max_samples+1)),3)        aas12, --aas_cluster
           TRUNC((count_queueing/(max_samples+1)),3)       aas13, --aas_queueing 
           count_total
    FROM
       (SELECT sid,
               serial#,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),-1,1)) count_cpu,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),0,1))  count_other,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),1,1))  count_application,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),2,1))  count_configuration,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),3,1))  count_administrative,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),4,1))  count_concurrency,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),5,1))  count_commit,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),7,1))  count_network,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),8,1))  count_user_io,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),9,1))  count_system_io,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),10,1)) count_scheduler,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),11,1)) count_cluster,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),12,1)) count_queueing,
               COUNT(*)                             count_total,
               MAX(lss_sample.nb_samples)           max_samples,
               MAX(user#)                           max_user#,
               MAX(program)                         max_program,
               MAX(con_id)                          max_con_id
        FROM lss$_sampling_session
        CROSS JOIN 
           (SELECT MAX(sample_id) - MIN(sample_id)  nb_samples
            FROM lss$_sampling_session
            WHERE sample_time >= SYSDATE -(10/24/60)
           ) lss_sample
        WHERE sample_time >= SYSDATE -(10/24/60)
        GROUP BY sid,
                 serial#
        ORDER BY count_total DESC
        FETCH FIRST 20 ROWS ONLY
        )

View creation – Step 3

Finally we will accumulate the different wait classes and cpu AAS for the top 20 activity sessions as follow:

CREATE OR REPLACE VIEW v$top_activity_session_lss
AS
SELECT sid,
       serial#,
       user#,
       user_program,
       user_con_id,
       count_total,
       aas1                                                                 C_CPU,
       aas1+aas2                                                            C_OTHER,
       aas1+aas2+aas3                                                       C_APPLICATION,
       aas1+aas2+aas3+aas4                                                  C_CONFIGURATION,
       aas1+aas2+aas3+aas4+aas5                                             C_ADMINISTRATIVE,
       aas1+aas2+aas3+aas4+aas5+aas6                                        C_CONCURRENCY,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7                                   C_COMMIT,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8                              C_NETWORK,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9                         C_USER_IO,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10                   C_SYSTEM_IO,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11             C_SCHEDULER,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12       C_CLUSTER,
       aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12+aas13 C_QUEUEING,
       MAX(aas1+aas2+aas3+aas4+aas5+aas6+aas7+aas8+aas9+aas10+aas11+aas12+aas13) OVER() MAX_AAS
FROM 
   (SELECT sid,
           serial#,
           max_user#   user#,
           max_program user_program,
           max_con_id  user_con_id,
           TRUNC((count_cpu/(max_samples+1)),3)            aas1,  --aas_cpu
           TRUNC((count_other/(max_samples+1)),3)          aas2,  --aas_other
           TRUNC((count_application/(max_samples+1)),3)    aas3,  --aas_application
           TRUNC((count_configuration/(max_samples+1)),3)  aas4,  --aas_configuration
           TRUNC((count_administrative/(max_samples+1)),3) aas5,  --aas_administrative
           TRUNC((count_concurrency/(max_samples+1)),3)    aas6,  --aas_concurrency
           TRUNC((count_commit/(max_samples+1)),3)         aas7,  --aas_commit
           TRUNC((count_network/(max_samples+1)),3)        aas8,  --aas_network
           TRUNC((count_user_io/(max_samples+1)),3)        aas9,  --aas_user_io
           TRUNC((count_system_io/(max_samples+1)),3)      aas10, --aas_system_io
           TRUNC((count_scheduler/(max_samples+1)),3)      aas11, --aas_scheduler
           TRUNC((count_cluster/(max_samples+1)),3)        aas12, --aas_cluster
           TRUNC((count_queueing/(max_samples+1)),3)       aas13, --aas_queueing 
           count_total
    FROM
       (SELECT sid,
               serial#,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),-1,1)) count_cpu,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),0,1))  count_other,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),1,1))  count_application,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),2,1))  count_configuration,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),3,1))  count_administrative,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),4,1))  count_concurrency,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),5,1))  count_commit,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),7,1))  count_network,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),8,1))  count_user_io,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),9,1))  count_system_io,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),10,1)) count_scheduler,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),11,1)) count_cluster,
               COUNT(DECODE(DECODE(session_state,'C',-1,wait_class#),12,1)) count_queueing,
               COUNT(*)                             count_total,
               MAX(lss_sample.nb_samples)           max_samples,
               MAX(user#)                           max_user#,
               MAX(program)                         max_program,
               MAX(con_id)                          max_con_id
        FROM lss$_sampling_session
        CROSS JOIN 
           (SELECT MAX(sample_id) - MIN(sample_id)  nb_samples
            FROM lss$_sampling_session
            WHERE sample_time >= SYSDATE -(10/24/60)
           ) lss_sample
        WHERE sample_time >= SYSDATE -(10/24/60)
        GROUP BY sid,
                 serial#
        ORDER BY count_total DESC
        FETCH FIRST 20 ROWS ONLY
        )
   );

Modified source query

We will modify the source query as follow:

        SELECT top_act.sid              SID
        ,      DECODE(top_act.user#,0,'SYS',1,'PUBLIC',cdb_users.username) USERNAME
        ,      top_act.user_program     USER_PROGRAM
        ,      DECODE(top_act.user_con_id,0,'CDB WIDE',cont.name) CONTAINER_NAME
        ,      top_act.c_cpu            C_CPU
        ,      top_act.c_other          C_OTHER
        ,      top_act.c_application    C_APPLICATION
        ,      top_act.c_configuration  C_CONFIGURATION
        ,      top_act.c_administrative C_ADMINISTRATIVE
        ,      top_act.c_concurrency    C_CONCURRENCY
        ,      top_act.c_commit         C_COMMIT
        ,      top_act.c_network        C_NETWORK
        ,      top_act.c_user_io        C_USER_IO
        ,      top_act.c_system_io      C_SYSTEM_IO
        ,      top_act.c_scheduler      C_SCHEDULER
        ,      top_act.c_cluster        C_CLUSTER
        ,      top_act.c_queueing       C_QUEUEING
        ,      top_act.max_aas          MAX_AAS
        FROM v$top_activity_session_lss top_act
        LEFT OUTER JOIN cdb_users 
          ON cdb_users.user_id = top_act.user#
         AND cdb_users.con_id = top_act.user_con_id
        LEFT OUTER JOIN v$containers cont
          ON cont.con_id = top_act.user_con_id
        ORDER BY top_act.count_total DESC, top_act.c_queueing DESC

In order to display the container name and the user name, we are using the v$containers and the cdb_users views. However, because the v$containers and cdb_users are views that contain data linked to several containers (CDB$ROOT, PDB’s) and because the common user C##LSS should see data of all those containers, we will set the CONTAINER_DATA attribute as follow:

SYS@orcl> ALTER USER C##LSS
  2  SET CONTAINER_DATA = (CDB$ROOT,PDB1)
  3  FOR v_$containers CONTAINER=CURRENT;

User altered.

SYS@orcl>

SYS@orcl> ALTER USER C##LSS
  2  SET CONTAINER_DATA = (CDB$ROOT,PDB1)
  3  FOR cdb_users CONTAINER=CURRENT;

User altered.

We have only restricted to the containers CDB$ROOT and PDB1.

XSLT processing

We will use the query defined in the part XVI as a starting point with the main following differences:

  • The X axis time value will be replaced by a session id value,
  • The graph bars will be horizontal instead of vertical in this case.

XSLT variables

We will add five additional variables in the XSLT document:

  • <xsl:variable name="bar_height">10</xsl:variable>

    Height of the horizontal bar,

  • <xsl:variable name="length_width">150</xsl:variable>

    Length of the horizontal bar,

  • <xsl:variable name="xval_min">0</xsl:variable>

    Minimun activity value,

  • <xsl:variable name="xval_max"><xsl:value-of select="/descendant::MAX_AAS[position()=1]"/>

    First value of the column MAX_AAS,

  • <xsl:variable name="session_nb"><xsl:value-of select="count(/descendant::SID)"/></xsl:variable>

    Number of occurrence of the column SID.

Furthermore:

  • The variable “margin_top” is set to 30,
  • The variable “margin_left” is set to 45,
  • The variable “graph_width” is set to ‘$length_width+$margin_left+$margin_right+210’,
  • The variable “graph_height” is set to ‘270+$margin_top+$margin_bottom’,
  • The variable “graph_name” is set to ‘LSS Top Activity Sessions (last 10 minutes) – CDB/PDB’.

Modified query

SET LINESIZE      300
SET LONGCHUNKSIZE 100000
SET LONG          100000

SET FEEDBACK OFF
SET VERIFY   OFF
SET PAGESIZE 0

SET HEADING OFF

SPOOL generate_svg_23f.svg

SELECT XMLTRANSFORM
   (DBMS_XMLGEN.GETXMLTYPE
      ('SELECT top_act.sid              SID
        ,      DECODE(top_act.user#,0,''SYS'',1,''PUBLIC'',cdb_users.username) USERNAME
        ,      top_act.user_program     USER_PROGRAM
        ,      DECODE(top_act.user_con_id,0,''CDB WIDE'',cont.name) CONTAINER_NAME
        ,      top_act.c_cpu            C_CPU
        ,      top_act.c_other          C_OTHER
        ,      top_act.c_application    C_APPLICATION
        ,      top_act.c_configuration  C_CONFIGURATION
        ,      top_act.c_administrative C_ADMINISTRATIVE
        ,      top_act.c_concurrency    C_CONCURRENCY
        ,      top_act.c_commit         C_COMMIT
        ,      top_act.c_network        C_NETWORK
        ,      top_act.c_user_io        C_USER_IO
        ,      top_act.c_system_io      C_SYSTEM_IO
        ,      top_act.c_scheduler      C_SCHEDULER
        ,      top_act.c_cluster        C_CLUSTER
        ,      top_act.c_queueing       C_QUEUEING
        ,      top_act.max_aas          MAX_AAS
        FROM v$top_activity_session_lss top_act
        LEFT OUTER JOIN cdb_users 
          ON cdb_users.user_id = top_act.user#
         AND cdb_users.con_id = top_act.user_con_id
        LEFT OUTER JOIN v$containers cont
          ON cont.con_id = top_act.user_con_id
        ORDER BY top_act.count_total DESC, top_act.c_queueing DESC')
,      XMLTYPE.CREATEXML
   (TO_CLOB(
    '<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     <xsl:variable name="margin_top">30</xsl:variable>
     <xsl:variable name="margin_bottom">30</xsl:variable>
     <xsl:variable name="margin_left">45</xsl:variable>
     <xsl:variable name="margin_right">100</xsl:variable>
     <xsl:variable name="bar_height">10</xsl:variable>
     <xsl:variable name="length_width">150</xsl:variable>
     <xsl:variable name="graph_width"><xsl:value-of select="$length_width+$margin_left+$margin_right+210"/></xsl:variable>
     <xsl:variable name="graph_height"><xsl:value-of select="270+$margin_top+$margin_bottom"/></xsl:variable>
     <xsl:variable name="graph_name">LSS Top Activity Sessions (last 10 minutes) - CDB/PDB</xsl:variable>
     <xsl:variable name="xval_min">0</xsl:variable>
     <xsl:variable name="xval_max"><xsl:value-of select="/descendant::MAX_AAS[position()=1]"/></xsl:variable>
     <xsl:variable name="session_nb"><xsl:value-of select="count(/descendant::SID)"/></xsl:variable>
       <xsl:template match="/">
         <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" width="{$graph_width}" height="{$graph_height}">
           <text x="{$margin_left+1}" y="{($margin_top)-20}" style="fill: #000000; stroke: none;font-size:10px;text-anchor=start"><xsl:value-of select="$graph_name"/></text>
           <text x="{($margin_left)-35}" y="{($margin_top)-5}" style="fill: #000000; stroke: none;font-size:8px;font-weight:bold;text-anchor=start">Session Id</text>
           <text x="{($margin_left)+1}" y="{($margin_top)-5}" style="fill: #000000; stroke: none;font-size:8px;font-weight:bold;text-anchor=start">Activity</text>
           <text x="{($margin_left)+160}" y="{($margin_top)-5}" style="fill: #000000; stroke: none;font-size:8px;font-weight:bold;text-anchor=start">User Name</text>
           <text x="{($margin_left)+240}" y="{($margin_top)-5}" style="fill: #000000; stroke: none;font-size:8px;font-weight:bold;text-anchor=start">Program Name</text>
           <text x="{($margin_left)+325}" y="{($margin_top)-5}" style="fill: #000000; stroke: none;font-size:8px;font-weight:bold;text-anchor=start">Container</text>
           <line x1="{($margin_left)-35}" y1="{($margin_top)-2+(($bar_height)+5)*(position()-1)}" x2="{($graph_width)-($margin_right)+10}" y2="{($margin_top)-2+(($bar_height)+5)*(position()-1)}" style="stroke:lightblue;stroke-width:1" />'
           ) 
    || 
    TO_CLOB(
          '<xsl:for-each select="ROWSET/ROW">
             <rect x="{($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{((($xval_min)-(descendant::C_CPU))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="limegreen" stroke="none"/> 
             <rect x="{((($xval_min)-(descendant::C_CPU))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_CPU)-(C_OTHER))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="hotpink" stroke="none"/>
             <rect x="{((($xval_min)-(descendant::C_OTHER))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_OTHER)-(C_APPLICATION))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="indianred" stroke="none"/>                                                                                                                                    
             <rect x="{((($xval_min)-(descendant::C_APPLICATION))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_APPLICATION)-(C_CONFIGURATION))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="olive" stroke="none"/>   
             <rect x="{((($xval_min)-(descendant::C_CONFIGURATION))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_CONFIGURATION)-(C_ADMINISTRATIVE))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="grey" stroke="none"/>   
             <rect x="{((($xval_min)-(descendant::C_ADMINISTRATIVE))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_ADMINISTRATIVE)-(C_CONCURRENCY))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="sienna" stroke="none"/>'
           ) 
    || 
    TO_CLOB(
          '  <rect x="{((($xval_min)-(descendant::C_CONCURRENCY))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_CONCURRENCY)-(C_COMMIT))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="orange" stroke="none"/>  
             <rect x="{((($xval_min)-(descendant::C_COMMIT))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_COMMIT)-(C_NETWORK))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="tan" stroke="none"/>   
             <rect x="{((($xval_min)-(descendant::C_NETWORK))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_NETWORK)-(C_USER_IO))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="royalblue" stroke="none"/>   
             <rect x="{((($xval_min)-(descendant::C_USER_IO))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_USER_IO)-(C_SYSTEM_IO))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="skyblue" stroke="none"/>   
             <rect x="{((($xval_min)-(descendant::C_SYSTEM_IO))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_SYSTEM_IO)-(C_SCHEDULER))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="lightcyan" stroke="none"/>   
             <rect x="{((($xval_min)-(descendant::C_SCHEDULER))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_SCHEDULER)-(C_CLUSTER))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="lightgray" stroke="none"/>   
             <rect x="{((($xval_min)-(descendant::C_CLUSTER))*(($length_width) div (($xval_min)-($xval_max))))+($margin_left)}" y="{$margin_top+(($bar_height)+5)*(position()-1)}" width="{(((descendant::C_CLUSTER)-(C_QUEUEING))*(($length_width) div (($xval_min)-($xval_max))))}" height="{$bar_height}" fill="bisque" stroke="none"/> 
             <text x="{($margin_left)-25}" y="{$margin_top+8+(($bar_height)+5)*(position()-1)}" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="(descendant::SID)"/></text>
             <text x="{($margin_left)+160}" y="{$margin_top+8+(($bar_height)+5)*(position()-1)}" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="(descendant::USERNAME)"/></text>
             <text x="{($margin_left)+240}" y="{$margin_top+8+(($bar_height)+5)*(position()-1)}" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="(descendant::USER_PROGRAM)"/></text>
             <text x="{($margin_left)+325}" y="{$margin_top+8+(($bar_height)+5)*(position()-1)}" style="fill: #000000; stroke: none;font-size:8px;text-anchor=start"><xsl:value-of select="(descendant::CONTAINER_NAME)"/></text>
             <line x1="{($margin_left)-35}" y1="{($margin_top)-2+(($bar_height)+5)*(position()-0)}" x2="{($graph_width)-($margin_right)+10}" y2="{($margin_top)-2+(($bar_height)+5)*(position()-0)}" style="stroke:lightblue;stroke-width:1" />
           </xsl:for-each>'
           ) 
    || 
    TO_CLOB(
          '<text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+0}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">CPU</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)-5}" width="{10}" height="{6}" fill="limegreen" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+8}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Other</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+3}" width="{10}" height="{6}" fill="hotpink" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+16}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Application</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+11}" width="{10}" height="{6}" fill="indianred" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+24}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Configuration</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+19}" width="{10}" height="{6}" fill="olive" stroke="black"/>   
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+32}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Administrative</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+27}" width="{10}" height="{6}" fill="gray" stroke="black"/>   
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+40}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Concurrency</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+35}" width="{10}" height="{6}" fill="sienna" stroke="black"/>'
           ) 
    || 
    TO_CLOB(
          '<text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+48}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Commit</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+43}" width="{10}" height="{6}" fill="orange" stroke="black"/>
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+56}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Network</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+51}" width="{10}" height="{6}" fill="tan" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+64}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">User IO</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+59}" width="{10}" height="{6}" fill="royalblue" stroke="black"/>  
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+72}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">System IO</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+67}" width="{10}" height="{6}" fill="skyblue" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+80}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Scheduler</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+75}" width="{10}" height="{6}" fill="lightcyan" stroke="black"/>
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+88}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Cluster</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+83}" width="{10}" height="{6}" fill="lightgray" stroke="black"/> 
           <text x="{($graph_width)-($margin_right)+33}" y="{($margin_top)+96}" style="fill:#000000; stroke: none;font-size:8px;text-anchor=start">Queueing</text>
           <rect x="{($graph_width)-($margin_right)+20}" y="{($margin_top)+91}" width="{10}" height="{6}" fill="bisque" stroke="black"/>                                                  
         </svg>
       </xsl:template>
     </xsl:stylesheet>'
           )
   )
   ) 
FROM dual;

SPOOL OFF
SET HEADING ON

SET VERIFY   ON
SET FEEDBACK ON

Result:

generate_svg_23f1

Remarks:

  • The query has been executed from the CDB$ROOT container by the C##LSS common user,
  • The v$top_activity_session_lss has been created from the CDB$ROOT container in the C##LSS schema.

Average Active Sessions and CDB – Light Sampling Sessions

Scope

Suppose that you have a 12c CDB database. An extra column “con_id” has been added to the view v$waitclassmetric, which is linked to the container identifier. Unfortunately connected as a common user to the container “CDB$ROOT” when you query this view the column “con_id” has always the value of 0 which means CDB wide.

If you want to know the details of the average active sessions by PDB, you could use the view v$active_session_history which belongs to ASH (Active Session History) but for the following reasons this view is not always usable or available:

  • You have an Oracle Database 9i release,
  • You have an Oracle Database Standard Edition,
  • You have an Oracle Database Enterprise Edition without the “Diagnostics Pack” licensed,
  • Etc.

Some open projects “simulate” ASH, we can quote L-ASH and S-ASH for example which can be found at the following address http://datavirtualizer.com/ash-masters/33-2/ . We will develop a “light” ASH like feature that will sample
the active sessions for CDB and non-CDB databases. We will first focus on CDB databases.

Light Sampling Sessions (LSS)

Every 5 seconds by default, we will save the active sessions of the v$session view from the CDB$ROOT container, into a specific table lss$_sampling_session. An active session is:

  • A session whose status is ACTIVE and,
  • (a session whose state is WAITING and the wait class is not IDLE) or (a session whose state is not WAITING).

In the rest of this post, we will make the assumption that we are using an Oracle Database 12cR1 Standard Edition One with only one PDB (single-tenant environment).

Remark:

LSS will not replace the ASH features. Instead it will give information about sampled active sessions.

CDB$ROOT tablespace creation

We will create a specific tablespace ‘LSS_REPOSITORY’ to host LSS. Let’s start with the CDB$ROOT container:

@> connect / as sysdba
Connected.
SYS@orcl> show con_name;

CON_NAME
------------------------------
CDB$ROOT
SYS@orcl> CREATE TABLESPACE "LSS_REPOSITORY" DATAFILE
  2  'C:\APP\ORACLE\ORADATA\ORCL\LSS_REPOSITORY01.DBF' SIZE 150 M
  3  AUTOEXTEND ON MAXSIZE 2 G
  4  LOGGING ONLINE PERMANENT BLOCKSIZE 8192
  5  EXTENT MANAGEMENT LOCAL AUTOALLOCATE DEFAULT NOCOMPRESS  SEGMENT SPACE MANAGEMENT AUTO;

Tablespace created.

PDB tablespace creation

We will create the same tablespace in all the PDB (PDB1 in our case):

SYS@orcl> ALTER SESSION SET CONTAINER=PDB1;

Session altered.

SYS@orcl> show con_name;

CON_NAME
------------------------------
PDB1
SYS@orcl> CREATE TABLESPACE "LSS_REPOSITORY" DATAFILE
  2  'C:\APP\ORACLE\ORADATA\ORCL\PDB1\LSS_REPOSITORY01.DBF' SIZE 5 M
  3  AUTOEXTEND ON MAXSIZE 2 G
  4  LOGGING ONLINE PERMANENT BLOCKSIZE 8192
  5  EXTENT MANAGEMENT LOCAL AUTOALLOCATE DEFAULT NOCOMPRESS  SEGMENT SPACE MANAGEMENT AUTO;

Tablespace created.

You could create this tablespace in all the PDB with a smaller size what we have done.

Common user creation

Connected to the CDB$ROOT container, we will create the C##LSS common user:

SYS@orcl> CREATE USER C##LSS IDENTIFIED BY lss
  2  CONTAINER=ALL
  3  DEFAULT TABLESPACE LSS_REPOSITORY
  4  QUOTA UNLIMITED ON LSS_REPOSITORY;

User created.

Base privileges

We will grant the following privileges to the C##LSS user:

SYS@orcl> GRANT CREATE SESSION      TO C##LSS;

Grant succeeded.

SYS@orcl> GRANT SELECT_CATALOG_ROLE TO C##LSS;

Grant succeeded.

SYS@orcl> GRANT CREATE PROCEDURE    TO C##LSS;

Grant succeeded.

SYS@orcl> GRANT CREATE VIEW         TO C##LSS;

Grant succeeded.

SYS@orcl> GRANT CREATE TABLE        TO C##LSS;

Grant succeeded.

Table creation

Let’s now create the table lss$_sampling_session in the C##LSS schema:

@> connect c##lss@orcl
Enter password:
Connected.
C##LSS@orcl> show con_name;

CON_NAME
------------------------------
CDB$ROOT
C##LSS@orcl> CREATE TABLE lss$_sampling_session
  2  AS
  3  SELECT CAST (1 AS NUMBER) sample_id,
  4         CAST (NULL AS DATE) sample_time,
  5         sid,
  6         serial#,
  7         user#,
  8         type,
  9         command,
 10         program,
 11         module,
 12         action,
 13         service_name,
 14         client_identifier,
 15         CAST ('1' AS CHAR(1)) session_state,
 16         state,
 17         event#,
 18         event,
 19         seq#,
 20         p1,
 21         p2,
 22         p3,
 23         wait_class#,
 24         wait_time_micro,
 25         sql_id,
 26         con_id
 27  FROM v$session
 28  WHERE 1=2;

Table created.

Other privileges

Let’s grant the SELECT privilege on the underlying object of the v$session view in order to use it in a procedure:

@> connect / as sysdba
Connected.
SYS@orcl> show con_name;

CON_NAME
------------------------------
CDB$ROOT
SYS@orcl> GRANT SELECT ON SYS.V_$SESSION TO C##LSS;

Grant succeeded.

Let’s grant the EXECUTE privilege on the DBMS_LOCK package:

SYS@orcl> GRANT EXECUTE ON DBMS_LOCK TO C##LSS;

Grant succeeded.

V$session is a view that contains data linked to several containers (CDB$ROOT, PDBs). Because the common user C##LSS should see data of all those containers we will set the CONTAINER_DATA attribute as follow:

SYS@orcl> ALTER USER C##LSS
  2  SET CONTAINER_DATA = (CDB$ROOT,PDB1)
  3  FOR v_$session CONTAINER=CURRENT;

User altered.

Like with the SELECT privilege, the target object is the underlying table of the v$session view.

Package specifications

Let’s create the package specifications as following:

CREATE OR REPLACE PACKAGE C##LSS.DBMS_SAMPLING_SESSION AS 

-- =======================================================================
--  Package       : DBMS_SAMPLING_SESSION
--  Description   : Sample active sessions
--  Author        : Arnaud Fargues
--  Creation      : 14.06.2015
--  Modifications : 
-- =======================================================================

   PROCEDURE start_sampling (
      p_sampling_window_min   IN NUMBER DEFAULT 60,
      p_sampling_interval_sec IN NUMBER DEFAULT 5);

END DBMS_SAMPLING_SESSION;
/
  • The first parameter is the sampling period time in minutes (default 60 minutes),
  • The second parameter is the sampling period interval in seconds (default 5 seconds).

Package body

You will find below the package body:

CREATE OR REPLACE PACKAGE BODY C##LSS.DBMS_SAMPLING_SESSION AS

PROCEDURE start_sampling (
   p_sampling_window_min   IN NUMBER DEFAULT 60,
   p_sampling_interval_sec IN NUMBER DEFAULT 5) 

-- =======================================================================
--  Procedure     : start_sampling
--  Description   : Starts sampling active sessions
--  Parameters    : p_sampling_window_min   : sampling period time in minutes
--                  p_sampling_interval_sec : sampling period interval in seconds
--  Author        : Arnaud Fargues
--  Creation      : 14.06.2015
--  Modifications : 
-- =======================================================================

AS
   v_nb_sample      INTEGER;
   v_index          INTEGER;
   v_cur_date       DATE;
   v_sample_id      NUMBER;
   v_sample_per_min NUMBER;
   v_session_sid    NUMBER;
BEGIN

   v_sample_per_min := 60 / p_sampling_interval_sec;
   v_nb_sample      := p_sampling_window_min * v_sample_per_min; 
   
   SELECT NVL(MAX(sample_id),0)
   INTO v_sample_id
   FROM lss$_sampling_session;
   
   SELECT SYS_CONTEXT ('USERENV', 'SID') 
   INTO v_session_sid
   FROM DUAL;
   
   FOR v_index IN 1..v_nb_sample
   LOOP
      v_sample_id := v_sample_id + 1;
      
      DBMS_APPLICATION_INFO.SET_MODULE( 
         module_name => 'DBMS_SAMPLING_SESSION', 
         action_name => 'Sample:'|| TO_CHAR(v_sample_id)); 
   
      v_cur_date := SYSDATE;

      INSERT INTO lss$_sampling_session(
         sample_id,    
         sample_time,  
         sid,          
         serial#,      
         session_state,
         state,
         user#,        
         type,         
         command,      
         program,      
         module,       
         action,       
         service_name, 
         client_identifier, 
         event#,       
         event,        
         seq#,         
         p1,           
         p2,           
         p3,           
         wait_class#,  
         wait_time_micro, 
         sql_id,       
         con_id)       
      SELECT 
         v_sample_id,
         v_cur_date,
         sid, 
         serial#,
         decode(state,'WAITING','W','C'),  
         state,
         user#,
         type,
         command,      
         program,
         module,
         action,
         service_name, 
         client_identifier, 
         event#,      
         event,        
         seq#,         
         p1,           
         p2,           
         p3,           
         wait_class#,  
         wait_time_micro, 
         sql_id,
         con_id 
      FROM v$session 
      WHERE status='ACTIVE'
        AND ((state = 'WAITING' AND wait_class# <> 6)
              OR (state <> 'WAITING' AND ((SID = v_session_sid AND event# <> 389) OR sid <> v_session_sid))); 
    
      IF v_index MOD v_sample_per_min = 0 THEN
         COMMIT; 
      END IF;
      
      DBMS_LOCK.SLEEP(p_sampling_interval_sec);
            
   END LOOP;
END start_sampling;

END DBMS_SAMPLING_SESSION;
/

Remarks:

  • The ‘wait_time’ column is deprecated since release 11gR1 and has been replaced with the columns ‘state’ and ‘wait_time_micro’,
  • The sampling data is commited every minute,
  • In an Oracle Database 11g release the con_id column of the select query could be replaced by 0,
  • I have only excluded the sampling session sid with the event 389 (‘PL/SQL lock timer’ event in 12cR1 database), but we could exclude this sampling session sid,
  • The package DBMS_APPLICATION_INFO has been used to track the sampling process,
  • Only a subset of columns of the v$session view has been sampled.

Usage:

We will connect to the C##LSS user in the CDB$ROOT container:

@> connect c##lss@orcl
Enter password:
Connected.
C##LSS@orcl> show con_name;

CON_NAME
------------------------------
CDB$ROOT
C##LSS@orcl> exec DBMS_SAMPLING_SESSION.start_sampling(p_sampling_window_min => 40);

Result:

C##LSS@orcl> SELECT CON_ID,
  2         COUNT(*)
  3  FROM LSS$_SAMPLING_SESSION
  4  GROUP BY CON_ID
  5  ORDER BY CON_ID;

    CON_ID   COUNT(*)
---------- ----------
         0         15
         1          7
         3        167

3 rows selected.

Generating SVG graphics with SQL*Plus – Part XIII – Horizontal bar graph

Horizontal bar graph

We will use an horizontal bar graph in order to display the space used by the permanent tablespaces. The base query will be defined as follow:

SELECT DTFL.TABLESPACE_NAME
,      (SELECT MAX(LENGTH(TABLESPACE_NAME)) FROM DBA_DATA_FILES) LEN_TABLESPACE_NAME
,      DTFL.TOTAL_SIZE/1024/1024 TOTAL_SPACE_MO 
,      FRSP.TOTAL_SIZE/1024/1024 FREE_SPACE_MO 
,      (DTFL.TOTAL_SIZE-FRSP.TOTAL_SIZE)/1024/1024 USED_SPACE_MO
,      TRUNC((DTFL.TOTAL_SIZE-FRSP.TOTAL_SIZE)/DTFL.TOTAL_SIZE*100,2) USED_PERCENT
FROM (
   SELECT TABLESPACE_NAME
   ,      SUM(BYTES) total_size 
   FROM DBA_DATA_FILES
   GROUP BY TABLESPACE_NAME) DTFL
LEFT OUTER JOIN (
   SELECT TABLESPACE_NAME
   ,      SUM(BYTES) total_size  
   FROM DBA_FREE_SPACE
   GROUP BY TABLESPACE_NAME) FRSP
ON FRSP.TABLESPACE_NAME=DTFL.TABLESPACE_NAME
ORDER BY DTFL.TABLESPACE_NAME

We have added the LEN_TABLESPACE_NAME column in order to display the tablespace names dynamically.

XSLT variables

First of all, we have the “common” variables that we often use:

  • margin_top,
  • margin_bottom,
  • margin_left,
  • margin_right,
  • graph_width,
  • graph_heigth.

We have also added new XSLT variables:

  • <xsl:variable name="bar_length">100</xsl:variable>

    Length of the horizontal bar,

  • <xsl:variable name="tablespace_nb"><xsl:value-of select="count(/descendant::TABLESPACE_NAME)"/></xsl:variable>

    Number of tablespaces,

  • <xsl:variable name="len_tblsp_name"><xsl:value-of select="/descendant::LEN_TABLESPACE_NAME[position()=1]"/></xsl:variable>

    Length of the tablespace names.

Threshold

We would like to display:

  • A green bar when the space used percentage is less than 85%,
  • An orange bar when the space used percentage is less than 97% and greater than 85%,
  • A red bar when the space used percentage is greater than 97%.

In order to achieve this we have used the XSLT variable “color_bar” and the conditional processing instruction “choose”. Note that we have used the code:

&gt;

for the > sign, which implies the DEFINE OFF instruction in the beginning of the script.

Modified query

You will find below the modified query:

SET LINESIZE      300
SET LONGCHUNKSIZE 30000
SET LONG          30000

SET FEEDBACK OFF
SET PAGESIZE 0

SET HEADING OFF
SET DEFINE  OFF

SPOOL generate_svg_13d.svg

SELECT XMLTRANSFORM
   (DBMS_XMLGEN.GETXMLTYPE
      ('SELECT DTFL.TABLESPACE_NAME
       ,      (SELECT MAX(LENGTH(TABLESPACE_NAME)) FROM DBA_DATA_FILES) LEN_TABLESPACE_NAME
       ,      DTFL.TOTAL_SIZE/1024/1024 TOTAL_SPACE_MO 
       ,      FRSP.TOTAL_SIZE/1024/1024 FREE_SPACE_MO 
       ,      (DTFL.TOTAL_SIZE-FRSP.TOTAL_SIZE)/1024/1024 USED_SPACE_MO
       ,      TRUNC((DTFL.TOTAL_SIZE-FRSP.TOTAL_SIZE)/DTFL.TOTAL_SIZE*100,2) USED_PERCENT
       FROM (
          SELECT TABLESPACE_NAME
          ,      SUM(BYTES) total_size 
          FROM DBA_DATA_FILES
          GROUP BY TABLESPACE_NAME) DTFL
       LEFT OUTER JOIN (
          SELECT TABLESPACE_NAME
          ,      SUM(BYTES) total_size  
          FROM DBA_FREE_SPACE
          GROUP BY TABLESPACE_NAME) FRSP
       ON FRSP.TABLESPACE_NAME=DTFL.TABLESPACE_NAME
       ORDER BY DTFL.TABLESPACE_NAME')
,      XMLTYPE.CREATEXML
   (TO_CLOB('<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     <xsl:variable name="margin_top">20</xsl:variable>
     <xsl:variable name="margin_bottom">30</xsl:variable>
     <xsl:variable name="margin_left">10</xsl:variable>
     <xsl:variable name="margin_right">200</xsl:variable>
     <xsl:variable name="bar_length">100</xsl:variable>
     <xsl:variable name="tablespace_nb"><xsl:value-of select="count(/descendant::TABLESPACE_NAME)"/></xsl:variable>
     <xsl:variable name="len_tblsp_name"><xsl:value-of select="/descendant::LEN_TABLESPACE_NAME[position()=1]"/></xsl:variable>
     <xsl:variable name="graph_width"><xsl:value-of select="600+$margin_left+$margin_right"/></xsl:variable>
     <xsl:variable name="graph_heigth"><xsl:value-of select="300+$margin_top+$margin_bottom"/></xsl:variable>
       <xsl:template match="/">
         <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" width="{$graph_width}" height="{$graph_heigth}">
           <text x="{($margin_left)+5}" y="{($margin_top)-5}" style="fill:#000000; stroke: none;font-size:12px;text-anchor=start">Permanent tablespaces space usage</text>
           <xsl:for-each select="ROWSET/ROW">
             <xsl:variable name="color_bar">
               <xsl:choose>
                 <xsl:when test="(descendant::USED_PERCENT)&gt;= 97">
                   <xsl:text>red</xsl:text>
                 </xsl:when>
                 <xsl:when test="(descendant::USED_PERCENT)&gt;= 85">
                   <xsl:text>orange</xsl:text>
                 </xsl:when>
                 <xsl:otherwise>
                   <xsl:text>lightgreen</xsl:text>
                 </xsl:otherwise>
               </xsl:choose>
             </xsl:variable>
             <text x="{($margin_left)+5}" y="{($margin_top)+(12*(position()))}" style="fill:#000000; stroke: none;font-size:10px;text-anchor=start"><xsl:value-of select="(descendant::TABLESPACE_NAME)"/></text>
             <rect x="{($margin_left)+($len_tblsp_name)*7}" y="{($margin_top)+(12*(position()-1))+3}" width="{(descendant::USED_PERCENT) * (($bar_length) div 100)}" height="9" fill="{$color_bar}" stroke="black"/>  
             <rect x="{($margin_left)+($len_tblsp_name)*7}" y="{($margin_top)+(12*(position()-1))+3}" width="{($bar_length)}" height="9" fill="none" stroke="black"/>   
             <text x="{($margin_left)+(($len_tblsp_name)*7)+($bar_length)+4}" y="{($margin_top)+(12*(position()))}" style="fill: #000000; stroke: none;font-size:10px;text-anchor=end"><xsl:value-of select="format-number((descendant::USED_PERCENT),''00.00'')"/>%</text>
           </xsl:for-each>
           <rect x="{($margin_left)+3}" y="{($margin_top)}" width="{($margin_left)+(($len_tblsp_name)*7)+($bar_length)+25}" height="{5+(($tablespace_nb)*12)}" fill="none" stroke="blue"/> 
         </svg>
       </xsl:template>
     </xsl:stylesheet>')
   )
   ) 
FROM dual;

SPOOL OFF
SET HEADING ON
SET DEFINE  ON

Result for “bar_length” = 100 :

generate_svg_13d_100

Result for “bar_length” = 150 :

generate_svg_13d_150

Remarks:

  • We are drawing in fact two rectangle objects. The first one for the filled color and the second one for the black contour,
  • The blue box is dynamically defined with respect to the number of tablespaces and the length of the tablespace names.