Sometimes a simple question turns out to be harder than expected.
“Can we see if a particular SQL execution in AWR used a baselined plan?”
Initial thoughts might be:
Q: Does DBMS_XPLAN.DISPLAY_AWR tell us this?
A: Apparently not. See below. This question could also be rephrased as two other possible questions:
Q:Isn’t there a column on DBA_HIST_SQLSTAT which tell us this?
A: No. You’d think there should be. There is a SQL_PROFILE column. There isn’t a SQL_PLAN_BASELINE column.
There also isn’t an EXACT_MATCHING_SIGNATURE although there is a FORCE_MATCHING_SIGNATURE.
Q: Is it in DBA_HIST_SQL_PLAN.OTHER_XML?
A. No although this is where DBMS_XPLAN.DISPLAY_AWR gets it’s notes about cardinality feedback and dynamic sampling from.
First of all, Let’s see that it’s not shown in DBMS_XPLAN.DISPLAY_AWR.
Let’s get a sql statement baselined, in AWR and not in memory.
The usual setup
SQL> create table t1 2 (col1 number 3 ,col2 varchar2(50) 4 ,flag varchar2(2)); Table created. SQL> insert into t1 2 select rownum 3 , lpad('X',50,'X') 4 , case when rownum = 1 5 then 'Y1' 6 when rownum = 2 7 then 'Y2' 8 when mod(rownum,2) = 0 9 then 'N1' 10 else 'N2' 11 end 12 from dual 13* connect by rownum <= 100000 SQL> / 100000 rows created. SQL> commit; Commit complete.
Get a plan and put it in a baseline:
SQL> var n varchar2(2); SQL> exec :n := 'N1'; PL/SQL procedure successfully completed. SQL> select count(*), max(col2) from t1 where flag = :n; select * from table(dbms_xplan.display_cursor); COUNT(*) MAX(COL2) ---------- -------------------------------------------------- 49999 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX SQL> select * from table(dbms_xplan.display_cursor); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID 731b98a8u0knf, child number 0 ------------------------------------- select count(*), max(col2) from t1 where flag = :n Plan hash value: 3724264953 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 221 (100)| | | 1 | SORT AGGREGATE | | 1 | 30 | | | |* 2 | TABLE ACCESS FULL| T1 | 50254 | 1472K| 221 (1)| 00:00:03 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("FLAG"=:N) Note ----- - dynamic sampling used for this statement (level=2) SQL> declare 2 l_op pls_integer; 3 begin 4 l_op := 5 dbms_spm.load_plans_from_cursor_cache('731b98a8u0knf'); 6* end; SQL> / PL/SQL procedure successfully completed.
Verify that DBMS_XPLAN.DISPLAY_CURSOR reports baseline usage:
SQL> select count(*), max(col2) from t1 where flag = :n; COUNT(*) MAX(COL2) ---------- -------------------------------------------------- 49999 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX SQL> select * from table(dbms_xplan.display_cursor); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID 731b98a8u0knf, child number 0 ------------------------------------- select count(*), max(col2) from t1 where flag = :n Plan hash value: 3724264953 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 221 (100)| | | 1 | SORT AGGREGATE | | 1 | 30 | | | |* 2 | TABLE ACCESS FULL| T1 | 50254 | 1472K| 221 (1)| 00:00:03 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("FLAG"=:N) Note ----- - dynamic sampling used for this statement (level=2) - SQL plan baseline SQL_PLAN_13w748wknkcwd616acf47 used for this statement
See that dynamic_sampling note most likely comes from OTHER_XML and Baseline note doesn’t, it comes from V$SQL:
SQL>select sql_id 2 , to_char(exact_matching_signature) sig 3 , plan_hash_value 4 , sql_plan_baseline 5 from v$sql 6* where sql_id = '731b98a8u0knf' SQL> / SQL_ID SIG PLAN_HASH_VALUE SQL_PLAN_BASELINE ------------- ---------------------------------------- --------------- ------------------------------ 731b98a8u0knf 1292784087274697613 3724264953 SQL_PLAN_13w748wknkcwd616acf47 SQL> set long 10000 SQL> select other_xml 2 from v$sql_plan 3 where sql_id = '731b98a8u0knf' 4* and other_xml is not null SQL> / OTHER_XML -------------------------------------------------------------------------------- <other_xml><info type="db_version">11.2.0.3</info><info type="parse_schema"><![C DATA["E668983_DBA"]]></info><info type="dynamic_sampling">2</info><info type="pl an_hash">3724264953</info><info type="plan_hash_2">1634389831</info><peeked_bind s><bind nam=":N" pos="1" dty="1" csi="178" frm="1" mxl="32">4e31</bind></peeked_ binds><outline_data><hint><![CDATA[IGNORE_OPTIM_EMBEDDED_HINTS]]></hint><hint><! [CDATA[OPTIMIZER_FEATURES_ENABLE('11.2.0.3')]]></hint><hint><![CDATA[DB_VERSION( '11.2.0.3')]]></hint><hint><![CDATA[OPT_PARAM('query_rewrite_enabled' 'false')]] ></hint><hint><![CDATA[ALL_ROWS]]></hint><hint><![CDATA[OUTLINE_LEAF(@"SEL$1")]] ></hint><hint><![CDATA[FULL(@"SEL$1" "T1"@"SEL$1")]]></hint></outline_data></oth er_xml>
Now, let’s add statement to AWR, do an AWR snap and flush the SP:
SQL> exec dbms_workload_repository.add_colored_sql('731b98a8u0knf'); PL/SQL procedure successfully completed. SQL> exec dbms_workload_repository.create_snapshot; PL/SQL procedure successfully completed. SQL> alter system flush shared_pool; System altered.
Now if we look back at the plan in memory, there’s nothing there.
SQL> select * from v$sql where sql_id = '731b98a8u0knf'; no rows selected SQL> select * from table(dbms_xplan.display_cursor('731b98a8u0knf')); PLAN_TABLE_OUTPUT ------------------------------------------------------------ SQL_ID: 731b98a8u0knf, child number: 0 cannot be found
But the SQL is in AWR and let’s see that DBMS_XPLAN.DISPLAY_AWR does not tells us that a baseline is used:
SQL> select * from table(dbms_xplan.display_awr('731b98a8u0knf')); PLAN_TABLE_OUTPUT --------------------------------------------------------------- SQL_ID 731b98a8u0knf -------------------- select count(*), max(col2) from t1 where flag = :n Plan hash value: 3724264953 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 221 (100)| | | 1 | SORT AGGREGATE | | 1 | 30 | | | | 2 | TABLE ACCESS FULL| T1 | 50238 | 1471K| 221 (1)| 00:00:03 | --------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2)
But it will tell us if a sql profile is used because it can via DBA_HIST_SQLSTAT.SQL_PROFILE – I leave that exercise to the reader.
So, back to the original question:
“Can we see if a particular SQL execution in AWR used a baselined plan?”
I’ve never needed to do this but as an exercise we can infer this connection by the presence of a baselined plan with the same phv2 but it’s convoluted.
It may be that there are simpler ways but it seems to me that we need to:
- Get the exact_matching_signature from the sql text
- Get the phv2 out of DBA_HIST_SQL_PLAN.OTHER_XML
- Match that phv2 with planid which is not exposed in DBA_SQL_PLAN_BASELINES but is in the underlying SYS.SQLOBJ$ tables
SQL> with subq_mysql as 2 (select sql_id 3 , (select dbms_sqltune.sqltext_to_signature(ht.sql_text) 4 from dual) sig 5 from dba_hist_sqltext ht 6 where sql_id = '731b98a8u0knf') 7 , subq_baselines as 8 (select b.signature 9 , b.plan_name 10 , b.accepted 11 , b.created 12 , o.plan_id 13 from subq_mysql ms 14 , dba_sql_plan_baselines b 15 , sys.sqlobj$ o 16 where b.signature = ms.sig 17 and o.signature = b.signature 18 and o.name = b.plan_name) 19 , subq_awr_plans as 20 (select sn.snap_id 21 , to_char(sn.end_interval_time,'DD-MON-YYYY HH24:MI') dt 22 , hs.sql_id 23 , hs.plan_hash_value 24 , t.phv2 25 , ms.sig 26 from subq_mysql ms 27 , dba_hist_sqlstat hs 28 , dba_hist_snapshot sn 29 , dba_hist_sql_plan hp 30 , xmltable('for $i in /other_xml/info 31 where $i/@type eq "plan_hash_2" 32 return $i' 33 passing xmltype(hp.other_xml) 34 columns phv2 number path '/') t 35 where hs.sql_id = ms.sql_id 36 and sn.snap_id = hs.snap_id 37 and sn.instance_number = hs.instance_number 38 and hp.sql_id = hs.sql_id 39 and hp.plan_hash_value = hs.plan_hash_value 40 and hp.other_xml is not null) 41 select awr.* 42 , nvl((select max('Y') 43 from subq_baselines b 44 where b.signature = awr.sig 45 and b.accepted = 'YES'),'N') does_baseline_exist 46 , nvl2(b.plan_id,'Y','N') is_baselined_plan 47 , to_char(b.created,'DD-MON-YYYY HH24:MI') when_baseline_created 48 from subq_awr_plans awr 49 , subq_baselines b 50 where b.signature (+) = awr.sig 51 and b.plan_id (+) = awr.phv2 52* order by awr.snap_id SQL> / SNAP_ID DT SQL_ID PLAN_HASH_VALUE PHV2 SIG D I WHEN_BASELINE_CRE ---------- ----------------- ------------- --------------- ---------- ---------- - - ----------------- 8703 05-FEB-2014 15:18 731b98a8u0knf 3724264953 1634389831 1.2928E+18 Y Y 05-FEB-2014 15:08 SQL>
Surprising.
Unless, of course, I’ve overlooked something bleeding obvious.
