If you’re familiar with SQL Profiles and SQL Baselines you may also know about SQL Patches – a feature that allows you to construct hints that you can attach to SQL statements at run-time without changing the code. Oracle 12c Release 2 introduces a couple of important changes to this feature:
- It’s now official – the feature had been copied from package dbms_sqldiag_internal to package dbms_sqldiag.
- The limitation of 500 characters has been removed from the hint text – it’s now a CLOB column.
H/T to Nigel Bayliss for including this detail in his presentation to the UKOUG last week, and pointing out that it’s also available for Standard Edition.
There are a couple of other little changes as you can see below from the two extract from the 12.2 declarations of dbms_sqldiag and dbms_sqldiag_internal below:
dbms_sqldiag ------------ FUNCTION CREATE_SQL_PATCH RETURNS VARCHAR2 Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- SQL_TEXT CLOB IN HINT_TEXT CLOB IN NAME VARCHAR2 IN DEFAULT DESCRIPTION VARCHAR2 IN DEFAULT CATEGORY VARCHAR2 IN DEFAULT VALIDATE BOOLEAN IN DEFAULT FUNCTION CREATE_SQL_PATCH RETURNS VARCHAR2 Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- SQL_ID VARCHAR2 IN HINT_TEXT CLOB IN NAME VARCHAR2 IN DEFAULT DESCRIPTION VARCHAR2 IN DEFAULT CATEGORY VARCHAR2 IN DEFAULT VALIDATE BOOLEAN IN DEFAULT dbms_sqldiag_internal --------------------- FUNCTION I_CREATE_PATCH RETURNS VARCHAR2 Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- SQL_ID VARCHAR2 IN HINT_TEXT CLOB IN CREATOR VARCHAR2 IN NAME VARCHAR2 IN DEFAULT DESCRIPTION VARCHAR2 IN DEFAULT CATEGORY VARCHAR2 IN DEFAULT VALIDATE BOOLEAN IN DEFAULT FUNCTION I_CREATE_PATCH RETURNS VARCHAR2 Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- SQL_TEXT CLOB IN HINT_TEXT CLOB IN CREATOR VARCHAR2 IN NAME VARCHAR2 IN DEFAULT DESCRIPTION VARCHAR2 IN DEFAULT CATEGORY VARCHAR2 IN DEFAULT VALIDATE BOOLEAN IN DEFAULT
- The function names change from i_create_patch to create_patch when exposed in dbms_sqldiag.
- There are two versions of the function – one that requires you to supply the exact SQL text, and a new version that allows you to supply an SQL ID.
- The internal function also adds a creator to the existing parameter list – and it doesn’t have a default so if you’ve already got some code to use the internal version it’s not going to work on an upgrade to 12.2 until you change it.
I was prompted to write this note by a tweet asking me if there’s any SQL available to see the contents of an SQL Profile in 11g and 12c. (I published some simple code several years ago for 10g, (before accepting – in the body of the blog, after accepting – in the linked comment) but Oracle changed the base tables in 11g). The answer is yes, probably on the Internet somewhere, but here’s some code I wrote a couple of years ago to report profiles in the more recent versions of Oracle:
rem rem sql_profile_baseline_11g.sql rem J.P.Lewis rem July 2010 rem set pagesize 60 set linesize 132 set trimspool on column hint format a70 wrap word column signature format 999,999,999,999,999,999,999 break on signature skip 1 on opt_type skip 1 on plan_id skip 1 spool sql_profile_baseline_11g select prf.signature, decode( obj_type, 1,'Profile', 2,'Baseline', 3,'Patch', 'Other' ) opt_type, prf.plan_id, extractvalue(value(tab),'.') hint from ( select /*+ no_eliminate_oby */ * from sqlobj$data where comp_data is not null order by signature, obj_type, plan_id ) prf, table( xmlsequence( extract(xmltype(prf.comp_data),'/outline_data/hint') ) ) tab ;
This will report the hints associated with SQL Baselines, SQL Profiles, and SQL Patches – all three store the data in the same base table. As a minor variation I also have a query that will reported a named profile/baseline/patch, but this requires a join to the sqlobj$ table. As you can see from the substitution variable near the end of the text, the script will prompt you for an object name.
set pagesize 60 set linesize 180 set trimspool on column plan_name format a32 column signature format 999,999,999,999,999,999,999 column category format a10 column hint format a70 wrap word break on plan_name skip 1 on signature skip 1 on opt_type skip 1 on category skip 1 on plan_id skip 1 spool sql_profile_baseline_11g select prf.plan_name, prf.signature, decode( obj_type, 1,'Profile', 2,'Baseline', 3,'Patch', 'Other' ) opt_type, prf.category, prf.plan_id, extractvalue(value(hnt),'.') hint from ( select /*+ no_eliminate_oby */ so.name plan_name, so.signature, so.category, so.obj_type, so.plan_id, sod.comp_data from sqlobj$ so, sqlobj$data sod where so.name = '&m_plan_name' and sod.signature = so.signature and sod.category = so.category and sod.obj_type = so.obj_type and sod.plan_id = so.plan_id order by signature, obj_type, plan_id ) prf, table ( select xmlsequence( extract(xmltype(prf.comp_data),'/outline_data/hint') ) from dual ) hnt ;
Lagniappe:
One of the enhancements that appeared in 12c for SQL Baselines was that the plan the baseline was supposed to produce was stored in the database so that Oracle could check that the baseline would still reproduce the expected plan before applying it. These plans (also generated for Profiles and Patches) are stored in the table sqlobj$plan, and the dbms_xplan package has been enhanced with three new functions to report them:
FUNCTION DISPLAY_SQL_PATCH_PLAN RETURNS DBMS_XPLAN_TYPE_TABLE Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- NAME VARCHAR2 IN FORMAT VARCHAR2 IN DEFAULT FUNCTION DISPLAY_SQL_PLAN_BASELINE RETURNS DBMS_XPLAN_TYPE_TABLE Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- SQL_HANDLE VARCHAR2 IN DEFAULT PLAN_NAME VARCHAR2 IN DEFAULT FORMAT VARCHAR2 IN DEFAULT FUNCTION DISPLAY_SQL_PROFILE_PLAN RETURNS DBMS_XPLAN_TYPE_TABLE Argument Name Type In/Out Default? ------------------------------ ----------------------- ------ -------- NAME VARCHAR2 IN FORMAT VARCHAR2 IN DEFAULT e.g. SQL> select * from table(dbms_xplan.display_sql_profile_plan('SYS_SQLPROF_015c9bd3bceb0000')); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- SQL text: select t1.id, t2.id from t1, t2 where t1.id between 10000 and 20000 and t2.n1 = t1.n1 and t2.n1 = t2.v2 -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- SQL Profile Name: SYS_SQLPROF_015c9bd3bceb0000 Status: ENABLED Plan rows: From dictionary -------------------------------------------------------------------------------- Plan hash value: 3683239666 ----------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib | ----------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 10501 | 287K| 248 (4)| 00:00:01 | | | | | 1 | PX COORDINATOR | | | | 0 (0)| | | | | | 2 | PX SEND QC (RANDOM) | :TQ10002 | 10501 | 287K| 248 (4)| 00:00:01 | Q1,02 | P->S | QC (RAND) | |* 3 | HASH JOIN BUFFERED | | 10501 | 287K| 248 (4)| 00:00:01 | Q1,02 | PCWP | | | 4 | PX RECEIVE | | 10002 | 97K| 123 (3)| 00:00:01 | Q1,02 | PCWP | | | 5 | PX SEND HASH | :TQ10000 | 10002 | 97K| 123 (3)| 00:00:01 | Q1,00 | P->P | HASH | | 6 | PX BLOCK ITERATOR | | 10002 | 97K| 123 (3)| 00:00:01 | Q1,00 | PCWC | | |* 7 | TABLE ACCESS FULL| T1 | 10002 | 97K| 123 (3)| 00:00:01 | Q1,00 | PCWP | | | 8 | PX RECEIVE | | 104K| 1845K| 124 (4)| 00:00:01 | Q1,02 | PCWP | | | 9 | PX SEND HASH | :TQ10001 | 104K| 1845K| 124 (4)| 00:00:01 | Q1,01 | P->P | HASH | | 10 | PX BLOCK ITERATOR | | 104K| 1845K| 124 (4)| 00:00:01 | Q1,01 | PCWC | | |* 11 | TABLE ACCESS FULL| T2 | 104K| 1845K| 124 (4)| 00:00:01 | Q1,01 | PCWP | | ----------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("T2"."N1"="T1"."N1") 7 - filter("T1"."ID"<=20000 AND "T1"."ID">=10000) 11 - filter("T2"."N1"=TO_NUMBER("T2"."V2")) Note ----- - automatic DOP: Computed Degree of Parallelism is 2
Disclaimer – I’ve checked only the SQL_PROFILE function call on 12.2, after creating a profile to check that my old 11g report still worked in 12c.
