{
  "date": "2016-01-21T10:33:06",
  "slug": "execution-plan-with-ash",
  "link": "https://www.dbi-services.com/blog/execution-plan-with-ash/",
  "title": {
    "rendered": "Execution Plan with ASH"
  },
  "content": {
    "rendered": "<h2>By Franck Pachot</h2>\n<p>.<br />\nHere is a query I use when I&#8217;m on a system that has Diagnostic Pack (ASH) but no tuning Pack (SQL Monitor).<br />\nIt displays the execution plan with dbms_xplan.display_cursor and adds the % of ASH samples in front of each plan operation.<br />\nHere is a small output example. Usual dbms_xplan output but showing the most active operation:<br />\n<a href=\"https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2022/04/CaptureXplanASH.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https://www.dbi-services.com/blog/wp-content/uploads/sites/2/2022/04/CaptureXplanASH.jpg\" alt=\"CaptureXplanASH\" width=\"1240\" height=\"264\" class=\"alignnone size-full wp-image-6706\" /></a><br />\n<!--more--><br />\nAs you see, you can quickly focus on the important part of a 3 pages execution plan. The part that is responsible for most of the response time.</p>\n<p>Query is here. Customize the first line to filter the statements you want.</p>\n<pre><code>\nwith \n \"sql\" as (select SQL_ID,CHILD_NUMBER,PLAN_HASH_VALUE,'' FORMAT from v$sql where sql_id='&amp;1'),\n \"ash\" as (\n          select sql_id,sql_plan_line_id,child_number,sql_plan_hash_value\n          ,round(count(*)/\"samples\",2) load \n          ,nvl(round(sum(case when session_state='ON CPU' then 1 end)/\"samples\",2),0) load_cpu\n          ,nvl(round(sum(case when session_state='WAITING' and wait_class='User I/O' then 1 end)/\"samples\",2),0) load_io\n          from \"sql\" join\n          (\n            select sql_id,sql_plan_line_id,sql_child_number child_number,sql_plan_hash_value,session_state,wait_class,count(*) over (partition by sql_id,sql_plan_hash_value) \"samples\" \n            FROM V$ACTIVE_SESSION_HISTORY \n          ) using(sql_id,child_number) group by sql_id,sql_plan_line_id,child_number,sql_plan_hash_value,\"samples\"\n ),\n \"plan\" as (\n        -- get dbms_xplan result\n        select \n         sql_id,child_number,n,plan_table_output\n         -- get plan line id from plan_table output\n         ,case when regexp_like (plan_table_output,'^[|][*]? *([0-9]+) *[|].*[|]$') then\n          regexp_replace(plan_table_output,'^[|][*]? *([0-9]+) *[|].*[|]$','\\1') \n          END SQL_PLAN_LINE_ID\n         from (select rownum n,plan_table_output,SQL_ID,CHILD_NUMBER from \"sql\", table(dbms_xplan.display_cursor(\"sql\".SQL_ID,\"sql\".CHILD_NUMBER,\"sql\".FORMAT)))\n )\nselect PLAN_TABLE_OUTPUT||CASE \n       -- ASH load to be displayed\n       WHEN LOAD &gt;0 THEN TO_CHAR(100*LOAD,'999')||'% (' || TO_CHAR(100*LOAD_CPU,'999')||'% CPU'|| TO_CHAR(100*LOAD_IO,'999')||'% I/O)'\n       -- header\n       WHEN REGEXP_LIKE (PLAN_TABLE_OUTPUT,'^[|] *Id *[|]')  THEN ' %ASH SAMPLES' \n       end plan_table_output\nfrom \"plan\" left outer join \"ash\" using(sql_id,child_number,sql_plan_line_id) order by sql_id,child_number,n \n</code></pre>\n<p>The idea is to simply parse the PLAN_TABLE_OUTPUT to get the LINE_ID and match that with the ASH SQL_PLAN_LINE_ID which by itself worth the price to buy Diagnostic Pack. Don&#8217;t hesitate to comment for improvement.<br />\nOriginally shared on <a href=\"http://www.dba-village.com/village/dvp_scripts.ScriptDetails?ScriptIdA=6108\">dba-village</a> as a view to create so it seems that I use it for about 5 years.</p>\n",
    "protected": false
  }
}
