mardi 21 février 2017

Plan Stability


In this entry, we’ll see how to correct Optimizer wrong decisions at the Kernel Level using Outlines or the new Feature SPM SQL Plan Management - Plan Stability.

1] Outlines

>> See at the botom as it is an old feature. <<

2] Plan Stability using DBMS_SPM

New Feature to ensure that the Elapsed time of a new Execution Plan won’t be worse than actual Execution Plan.

 

Many possibilities when we deal with Execution Plan to fix it to a good one :

 

[ 2.1 ] We already have a correct Plan In-Memory and we don’t want the Optimizer to change it anymore.

 

[ 2.2 ] A correct Plan exists In-Memory, but for another SQL_ID.

 

[ 3 ] We have a good Plan for the SQL_ID in the Past in the Workload Repository

3.1 in the same DB

3.2 and possibly in another Database !

 

 



Every Procedure are ran connected AS SYSDBA :

 

DBMS_SQLTUNE.CREATE_SQLSET

DBMS_SQLTUNE.create_stgtab_sqlset

DBMS_SQLTUNE.pack_stgtab_sqlset

DBMS_SQLTUNE.unpack_stgtab_sqlset

 

2.1 Create an SQL Plan Baseline for a given SQL_ID from a Plan in Memory

 

[ DBMS_SPM.load_plans_from_cursor_cache ]

 

select first_load_time,sql_id, plan_hash_value, HASH_VALUE, CHILD_NUMBER from v$sql where sql_id = 'cy9s9a39198u3'

 

2021-08-05/08:29:33     cy9s9a39198u3 1327504843 -> Good

 

set serveroutput on

DECLARE

  l_plans_loaded  PLS_INTEGER;

BEGIN

  l_plans_loaded := DBMS_SPM.load_plans_from_cursor_cache(

    sql_id => 'cy9s9a39198u3');

END;

/

 

If needed, Remove SQL_ID from Memory to get new SPM Plan

select address , HASH_VALUE from v$sql where sql_id = 'cy9s9a39198u3'

07000102C9A190D0    3524567875

 

exec DBMS_SHARED_POOL.PURGE ('07000102C9A190D0,3524567875','C');

 

Check for SPM Plan

 

SELECT sql_handle, plan_name, enabled, accepted , origin, created , last_executed  FROM   dba_sql_plan_baselines

SQL_6de9e1edf73dcb7c    SQL_PLAN_6vug1xrvmvkvw3c76d2c9    YES    YES    MANUAL-LOAD    05/08/2021 08:43:28,000000    05/08/2021 08:47:55,000000 --> OK

 

2.2 Create an SQL Plan Baseline from a good Plan of another SQL_ID in Memory

 

[ DBMS_SPM.load_plans_from_cursor_cache

  DBMS_SPM.DROP_SQL_PLAN_BASELINE ]

- SQL_ID with wrong Plan = 1hygduv1g12wm

SELECT sql_handle, plan_name, enabled, accepted , origin, created , last_executed, sql_text  FROM   dba_sql_plan_baselines order by created

SQL_621c9bd73edc6464    SQL_PLAN_6474vuwzdst347f17ff1d    YES    YES    MANUAL-LOAD-FROM-STS    15/03/2022 11:26:50,562621    15/03/2022 11:28:03,000000    (HUGECLOB)

- SQL_ID : fp4wf6h10698b with Good Plan : 3150554415

This SQL_ID is already fixed with a SPM, but it doesn’t need to be. If it is not already fixed by SPM, create the SPM as first step :


  • Create an SPM for the SQL_ID with Wrong Plan

 

set serveroutput on

DECLARE

  l_plans_loaded  PLS_INTEGER;

BEGIN

  l_plans_loaded := DBMS_SPM.load_plans_from_cursor_cache(

    sql_id => '1hygduv1g12wm');

END;

/

Get values from newly created SPM :

SELECT sql_handle, plan_name, enabled, accepted , origin, created , last_executed, sql_text  FROM   dba_sql_plan_baselines order by created

  • Put SPM with Correct Plan into SPM with Wrong Plan : 

SET SERVEROUTPUT ON

DECLARE

  l_plans_loaded  PLS_INTEGER;

BEGIN

  l_plans_loaded := DBMS_SPM.load_plans_from_cursor_cache(

    sql_id => '<SQL_ID_with_Correct_Plan>',

    plan_hash_value => '<Correct_Plan>',

    sql_handle => 'SQL Handle from SPM of the SQL_ID with Wrong Plan');

  DBMS_OUTPUT.put_line('Plans Loaded: ' || l_plans_loaded);

END;

/

 Ex: 

SET SERVEROUTPUT ON

DECLARE

  l_plans_loaded  PLS_INTEGER;

BEGIN

  l_plans_loaded := DBMS_SPM.load_plans_from_cursor_cache(

    sql_id => 'fp4wf6h10698b',

    plan_hash_value => '3150554415',

    sql_handle => 'SQL_03b57094971cdecb');

  DBMS_OUTPUT.put_line('Plans Loaded: ' || l_plans_loaded);

END;

/

A new SPM is created.

SELECT sql_handle, plan_name, enabled, accepted , origin, created , last_executed, sql_text  FROM   dba_sql_plan_baselines order by created

SQL_621c9bd73edc6464    SQL_PLAN_6474vuwzdst347f17ff1d    YES    YES    MANUAL-LOAD-FROM-STS    15/03/2022 11:26:50,562621    15/03/2022 11:28:03,000000    (HUGECLOB)

---> SQL_ID with Good Plan

SQL_03b57094971cdecb    SQL_PLAN_07dbhkkbjtrqb7f17ff1d    YES    YES    MANUAL-LOAD-FROM-CURSOR-CACHE    15/03/2022 11:50:37,871564        (HUGECLOB)


---> SQL_ID with wrong Plan ( the first created )

Then Drop the previous SPM with wrong Plan : 

SET SERVEROUTPUT ON

declare

drop_result pls_integer;

begin

drop_result := DBMS_SPM.DROP_SQL_PLAN_BASELINE(

sql_handle => 'SQL_03b57094971cdecb',

plan_name => 'SQL_PLAN_07dbhkkbjtrqbc4ac00a5');

dbms_output.put_line(drop_result);

end;

/

 

If needed, Purge Wrong Plan from Memory to allow SPM to be chosen

select address , HASH_VALUE from v$sql where sql_id = '1hygduv1g12wm '

0700010012D7AEE0 1252826228

exec DBMS_SHARED_POOL.PURGE ('0700010012D7AEE0,1252826228','C');

SELECT sql_handle, plan_name, enabled, accepted , origin, created , last_executed, sql_text  FROM   dba_sql_plan_baselines order by created

SQL_621c9bd73edc6464  SQL_PLAN_6474vuwzdst347f17ff1d      YES    YES    MANUAL-LOAD-FROM-STS  15/03/2022 11:26:50,562621       15/03/2022 11:28:03,000000   (HUGECLOB)

SQL_03b57094971cdecb  SQL_PLAN_07dbhkkbjtrqb7f17ff1d      YES    YES    MANUAL-LOAD-FROM-CURSOR-CACHE       15/03/2022 11:50:37,871564   15/03/2022 11:54:47,000000   (HUGECLOB)

SQL_03b57094971cdecb  SQL_PLAN_07dbhkkbjtrqb3ab19b62      YES    NO     AUTO-CAPTURE  15/03/2022 11:54:47,426884             (HUGECLOB)

Check the execution of SQL_ID :

select sql_id , plan_hash_value , parsing_schema_name , executions , ceil(buffer_gets/executions) ,

disk_reads , first_load_time , rows_processed , ceil(elapsed_time/1000000/60) Min , last_load_time , sql_text from v$sql

where sql_id = '1hygduv1g12wm'

OK < 1000 blocks

 

3.1 Create an SQL Plan Baseline for a given SQL_ID from a past Plan in AWR

 

DBMS_SQLTUNE.CREATE_SQLSET

DBMS_SQLTUNE.SELECT_WORKLOAD_REPOSITORY

dbms_spm.load_plans_from_sqlset

 

Note, new feature is not working :

With 12cR2, SPM plan baseline from AWR historical execution plans can be loaded, using DBMS_SPM.LOAD_PLANS_FROM_AWR.

 

variable x number

begin

:x := dbms_spm.load_plans_from_awr( begin_snap=>18416,end_snap=>18417,

basic_filter=>'sql_id = ''1hygduv1g12wm'' AND plan_hash_value = 3150554415' );

end;

/

 

ERROR at line 1:

ORA-13769: Snapshots 18416 and 18417 do not exist.

 

Too bad.

OK, let’s start, first, identify which snam_id have good plan :

 

SQL_ID = 'fp4wf6h10698b'

 

SELECT   sn.snap_id,

TO_CHAR(sn.begin_interval_time,'MM DD') "DAY", s.sql_id, plan_hash_value , module,

         ROUND (sum(s.buffer_gets_delta) / 1000000, 2) "BG(M)",

         ROUND (sum(s.disk_reads_delta) / 1000, 2)      "DK(K)",

         ROUND (sum(s.cpu_time_delta) / 1000000, 2)     "CPU(s)",

         ROUND (sum(s.elapsed_time_delta) / 1000000/60, 2)  "ELAPSED(min)",

         sum(s.fetches_delta)                             "FETCH",

         sum(s.rows_processed_delta)                      "ROWS",

         sum(s.executions_delta)                          "EXEC",

         ROUND (sum(s.buffer_gets_delta) / DECODE (sum(s.executions_delta), 0, 1, sum(s.executions_delta)))      "BG/EXEC",

         ROUND (sum(s.disk_reads_delta) / DECODE (sum(s.executions_delta), 0, 1, sum(s.executions_delta)))       "DK/EXEC",

         ROUND (sum(s.cpu_time_delta) / DECODE (sum(s.executions_delta), 0, 1, sum(s.executions_delta)) / 1000000, 3 )     "CPU(s)/EXEC",

         ROUND (sum(s.elapsed_time_delta) / DECODE (sum(s.executions_delta), 0, 1, sum(s.executions_delta)) / 1000000,3 )  "ELAPSED(s)/EXEC",

         ROUND (sum(s.disk_reads_delta)/DECODE(sum(s.buffer_gets_delta),0,1,sum(s.buffer_gets_delta))*100, 2)    "DK%BG",

         ROUND (sum(s.cpu_time_delta)/DECODE(sum(s.elapsed_time_delta),0,1,sum(s.elapsed_time_delta))*100, 2)    "CPU%ELAP"  

FROM     dba_hist_sqlstat s, dba_hist_snapshot sn

   WHERE    s.snap_id=sn.snap_id

            AND sn.begin_interval_time >= trunc(sysdate-60)

            AND sql_id in ('fp4wf6h10698b')

GROUP BY sn.snap_id,TO_CHAR(sn.begin_interval_time,'MM DD'), s.sql_id, plan_hash_value , module

ORDER BY TO_CHAR(sn.begin_interval_time,'MM DD'), s.sql_id, plan_hash_value , module

 

Same day, 2 plans :

 

snap_id date    sql_id          plan hash value BufferGets / exec

18575    03 15    fp4wf6h10698b    3150554415       768 à Good Plan

18576    03 15    fp4wf6h10698b    3150554415       978

18577    03 15    fp4wf6h10698b    1445784707    330818

  

In case, there is only one line in AWR, plug DBMS_SQLTUNE.SELECT_WORKLOAD_REPOSITORY(snap_id-1, snap_id

 

Create SQL Tunig Set and populate from AWR.

 

set serveroutput on

exec DBMS_SQLTUNE.CREATE_SQLSET('SAS_fp4wf6h10698b');

declare

baseline_ref_cursor DBMS_SQLTUNE.SQLSET_CURSOR;

begin

open baseline_ref_cursor for

select VALUE(p) from table(DBMS_SQLTUNE.SELECT_WORKLOAD_REPOSITORY(18575,18576,'sql_id='||CHR(39)||'fp4wf6h10698b'||CHR(39)||' and plan_hash_value=3150554415',NULL,NULL,NULL,NULL,NULL,NULL,'ALL')) p;

DBMS_SQLTUNE.LOAD_SQLSET('SAS_fp4wf6h10698b', baseline_ref_cursor);

end;

/

 

Double check the SQL Set :

 

SELECT NAME,OWNER,CREATED,STATEMENT_COUNT FROM DBA_SQLSET where name='SAS_fp4wf6h10698b';

 

select sqlset_name, sql_id, plan_hash_value from dba_sqlset_statements ;

 

SQLSET_NAME                    SQL_ID        PLAN_HASH_VALUE

------------------------------ ------------- ---------------

SAS_fp4wf6h10698b              fp4wf6h10698b      3150554415

 

Then Load SPM.

 

SELECT NAME,OWNER,CREATED,STATEMENT_COUNT FROM DBA_SQLSET where name='SAS_fp4wf6h10698b';

select count(*) from dba_sql_plan_baselines -- 0

 

set serveroutput on

declare

my_integer pls_integer;

begin

my_integer := dbms_spm.load_plans_from_sqlset(sqlset_name => 'SAS_fp4wf6h10698b',

                                              sqlset_owner => 'SYS',

                                              fixed => 'NO',

                                              enabled => 'YES');

 

DBMS_OUTPUT.PUT_line('Number of plans loaded: ' || my_integer);

end;

/

 The output should be “1” plan loaded.

 

Purge Shared Pool from the SQL_ID to get new SMP.

 

select 'exec DBMS_SHARED_POOL.PURGE ('''||ADDRESS||', '||HASH_VALUE||''', ''C'');' from V$SQLAREA where SQL_ID in ('fp4wf6h10698b')

 

exec DBMS_SHARED_POOL.PURGE ('0700010028942AF0, 3270544275', 'C');

 

3.2.1 Create an SQL Plan Baseline for a given SQL_ID from a Plan in AWR of Another DB

 

Source DBMS_SQLTUNE.CREATE_SQLSET

Source DBMS_SQLTUNE.SELECT_WORKLOAD_REPOSITORY / DBMS_SQLTUNE.LOAD_SQLSET

Source DBMS_SQLTUNE.create_stgtab_sqlset

Source DBMS_SQLTUNE.pack_stgtab_sqlset

expdp / impdp

Target DBMS_SQLTUNE.unpack_stgtab_sqlset

Target DBMS_SPM.load_plans_from_sqlset

Source DBMS_SQLTUNE.drop_sqlset

 

3.2.1.1 Populate the STS from Source DB

 

Ø  From a Plan found in an AWR Snap using DBMS_SQLTUNE.SELECT_WORKLOAD_REPOSITORY.

 

--This will create an empty SQL Tuning set.

 

exec DBMS_SQLTUNE.CREATE_SQLSET('DTM_SCHEMA_MERGE');

declare

baseline_ref_cursor DBMS_SQLTUNE.SQLSET_CURSOR;

begin

open baseline_ref_cursor for

select VALUE(p) from table(DBMS_SQLTUNE.SELECT_WORKLOAD_REPOSITORY(42178, 42179,'sql_id='||CHR(39)||'d787swkmh37kg'||CHR(39)||' and plan_hash_value=2371152508',NULL,NULL,NULL,NULL,NULL,NULL,'ALL')) p;

DBMS_SQLTUNE.LOAD_SQLSET('DTM_SCHEMA_MERGE', baseline_ref_cursor);

end;

/

 

SELECT NAME,OWNER,CREATED,STATEMENT_COUNT FROM DBA_SQLSET where name='DTM_SCHEMA_MERGE';

select count(*) from dba_sql_plan_baselines -- 0

 

3.2.1.2 Transfer to target DB

 

Create stgtab sqlset_tab table in DTM_SCHEMA schema:

 

BEGIN

DBMS_SQLTUNE.create_stgtab_sqlset(table_name => 'SQLSET_TAB',  schema_name => 'DTM_SCHEMA',  tablespace_name => 'USERS');

END;

/

 

Pack STS into the stgtab From SYS

 

BEGIN

DBMS_SQLTUNE.pack_stgtab_sqlset(sqlset_name => 'DTM_SCHEMA_MERGE', sqlset_owner => 'SYS', staging_table_name => 'SQLSET_TAB', staging_schema_owner => 'DTM_SCHEMA');

END;

/

 

Transfer the table containing the SQL SET (SQLSET_TAB) table to the TEST system

 

expdp SYSTEM DIRECTORY=BI_DB_DP_DIR DUMPFILE=SQLSET_TAB.dmp TABLES=DTM_SCHEMA.SQLSET_TAB

BI_DB srv:/home/comp/oracle > impdp system@PPR_BI_DB DIRECTORY=PPR_BI_DB_DP_DIR DUMPFILE=SQLSET_TAB.dmp

 

UNPACK THE SQLSET_TAB TABLE IN THE TEST SYSTEM

 

BEGIN

DBMS_SQLTUNE.unpack_stgtab_sqlset(sqlset_name => 'DTM_SCHEMA_MERGE',

sqlset_owner => 'SYS',

replace => TRUE,

staging_table_name => 'SQLSET_TAB',

staging_schema_owner => 'DTM_SCHEMA');

END;

/

 

Now the SQL Tuning Set is transferred successfully to another database without any issues.

 

3.2.1.3 Load the Sql Plan Baseline from STS

 

set serveroutput on

declare

my_integer pls_integer;

begin

my_integer := dbms_spm.load_plans_from_sqlset(sqlset_name => 'DTM_SCHEMA_MERGE',

                                              sqlset_owner => 'SYS',

                                              fixed => 'NO',

                                              enabled => 'YES');

DBMS_OUTPUT.PUT_line(my_integer);

end;

/

 

select count(*) from dba_sql_plan_baselines;

 

3.2.2 Another example of SPM from AWR

 

Case [ 3 ] I have a good Plan in AWR from another database, same SQL_ID.

 

Ex :

SQL_ID 7934fsmpydkwa

Target Environment PPR 3Hours 5000 exec. 270K BG / execution PHV: 3116998891 KO

Source Environment PRO 11Min. 5800 exec. 023K BG / execution PHV: 1688580575 OK

 

Connected as SYSDBA

 

Source : create SQLSet

Source : Load Plan from AWR into SQLSet

Transport SQLSet

Target : load SQLSet

 

Source Env : First create a SQLSet

 

SET SERVEROUTPUT ON

exec dbms_sqltune.create_sqlset(sqlset_name => '7934fsmpydkwa_sqlset_test',description => 'sqlset MYAPP SIMUMENS');

 

Get snap_id from AWR

 

SELECT   sn.snap_id,

TO_CHAR(sn.begin_interval_time,'MM DD') "DAY", s.sql_id, plan_hash_value , module,

         ROUND (sum(s.buffer_gets_delta) / 1000000, 2) "BG(M)",

         ROUND (sum(s.disk_reads_delta) / 1000, 2)      "DK(K)",

         ROUND (sum(s.cpu_time_delta) / 1000000, 2)     "CPU(s)",

         ROUND (sum(s.elapsed_time_delta) / 1000000/60, 2)  "ELAPSED(min)",

         sum(s.fetches_delta)                             "FETCH",

         sum(s.rows_processed_delta)                      "ROWS",

         sum(s.executions_delta)                          "EXEC",

         ROUND (sum(s.buffer_gets_delta) / DECODE (sum(s.executions_delta), 0, 1, sum(s.executions_delta)))      "BG/EXEC",

         ROUND (sum(s.disk_reads_delta) / DECODE (sum(s.executions_delta), 0, 1, sum(s.executions_delta)))       "DK/EXEC",

         ROUND (sum(s.cpu_time_delta) / DECODE (sum(s.executions_delta), 0, 1, sum(s.executions_delta)) / 1000000, 3 )     "CPU(s)/EXEC",

         ROUND (sum(s.elapsed_time_delta) / DECODE (sum(s.executions_delta), 0, 1, sum(s.executions_delta)) / 1000000,3 )  "ELAPSED(s)/EXEC",

         ROUND (sum(s.disk_reads_delta)/DECODE(sum(s.buffer_gets_delta),0,1,sum(s.buffer_gets_delta))*100, 2)    "DK%BG",

         ROUND (sum(s.cpu_time_delta)/DECODE(sum(s.elapsed_time_delta),0,1,sum(s.elapsed_time_delta))*100, 2)    "CPU%ELAP"  

FROM     dba_hist_sqlstat s, dba_hist_snapshot sn

   WHERE    s.snap_id=sn.snap_id

            AND sn.begin_interval_time >= trunc(sysdate-60)

            AND sql_id in ('7934fsmpydkwa')

GROUP BY sn.snap_id,TO_CHAR(sn.begin_interval_time,'MM DD'), s.sql_id, plan_hash_value , module

ORDER BY TO_CHAR(sn.begin_interval_time,'MM DD'), s.sql_id, plan_hash_value , module

 

62651    12 09    7934fsmpydkwa    1688580575    SQL*Plus    12.35    0.5    22.2    1.07    536    536    536    23040    1    0.041    0.12    0    34.52

62652    12 09    7934fsmpydkwa    1688580575    SQL*Plus    93.93    12.22    166.45    7.34    3437    3437    3437    27330    4    0.048    0.128    0.01    37.8

62653    12 09    7934fsmpydkwa    1688580575    SQL*Plus    30.17    3.58    51.68    2.7    1837    1837    1837    16426    2    0.028    0.088    0.01    31.88

 

Or select snap_id,sql_id,plan_hash_value from dba_hist_sqlstat where sql_id ='7934fsmpydkwa ' order by 1

 

Load Plan into SQL_Set

 

declare

baseline_ref_cur DBMS_SQLTUNE.SQLSET_CURSOR;

begin

open baseline_ref_cur for

select VALUE(p) from table(

DBMS_SQLTUNE.SELECT_WORKLOAD_REPOSITORY(62651, 62653,'sql_id='||CHR(39)||'7934fsmpydkwa'||CHR(39)||' and plan_hash_value=1688580575',NULL,NULL,NULL,NULL,NULL,NULL,'ALL')) p;

DBMS_SQLTUNE.LOAD_SQLSET('7934fsmpydkwa_sqlset_test', baseline_ref_cur);

end;

/

 

display SQL_Set

SELECT SQL_ID, PARSING_SCHEMA_NAME AS "SCH", SQL_TEXT, ELAPSED_TIME AS "ELAPSED", BUFFER_GETS FROM   TABLE( DBMS_SQLTUNE.SELECT_SQLSET( 'SQLT_WKLD_STS' ) );

 

Transport SQLSet from one database to another one.

 

BEGIN

DBMS_SQLTUNE.CREATE_STGTAB_SQLSET (table_name => 'MYAPP_SIMUMENS_7934', schema_name => 'ADB');

END;

/

BEGIN

DBMS_SQLTUNE.PACK_STGTAB_SQLSET (

 sqlset_name => '7934fsmpydkwa_sqlset_test',

 sqlset_owner => 'SYS',

 staging_table_name => 'MYAPP_SIMUMENS_7934',

 staging_schema_owner => 'ADB'

);

END;

/

 

expdp system/$psw directory=DP_DIR tables=ADB.MYAPP_SIMUMENS_7934 dumpfile=MYAPP_SIMUMENS_7934fsmpydkwa.DMP logfile=e_MYAPP_SIMUMENS_7934fsmpydkwa.log

 

Target DB

 

SYSDBA

 

impdp system/$psw directory=DP_DIR dumpfile=MYAPP_SIMUMENS_7934fsmpydkwa.DMP logfile=i_MYAPP_SIMUMENS_7934fsmpydkwa.log

 

Unpack staging table

 

set serveroutput on

BEGIN

DBMS_SQLTUNE.UNPACK_STGTAB_SQLSET (

sqlset_name => '%'

, sqlset_owner => 'SYS'

, replace => true

, staging_table_name => 'MYAPP_SIMUMENS_7934'

, staging_schema_owner => 'ADB');

END;

/

 

Load SQL_Set to SPM

 

 

VARIABLE v_plan_cnt NUMBER

EXECUTE :v_plan_cnt := DBMS_SPM.LOAD_PLANS_FROM_SQLSET( -

sqlset_name => '7934fsmpydkwa_sqlset_test', -

sqlset_owner => 'SYS', -

basic_filter => 'sql_id = ''7934fsmpydkwa'' AND plan_hash_value = 1688580575' );

 

Check

 

SELECT sql_handle, plan_name, enabled, accepted , origin, created , last_executed, sql_text  FROM   dba_sql_plan_baselines order by created

 

SQL_3ca35f91cc474453    SQL_PLAN_3t8uzk764fj2m711241d1    YES    YES    MANUAL-LOAD    12/01/2022 15:06:09.000000        (HUGECLOB)

 

Flush the two SQLs from the shared pool, so that the optimizer will pick the new plan

select 'exec DBMS_SHARED_POOL.PURGE ('''||ADDRESS||', '||HASH_VALUE||''', ''C'');' from V$SQLAREA where SQL_ID in ('2t8gdjy0pbs57');

exec SYS.DBMS_SHARED_POOL.PURGE ('0000001006B396C8, 2113289046', 'C');

 

Clean up Source

 

BEGIN

DBMS_SQLTUNE.drop_sqlset (sqlset_name => '7934fsmpydkwa_sqlset_test');

END;

/

 

2.4 SPM Administration

 

2.4.1 Drop an existing SPM Plan, using SQL_HANDLE.

 

-- SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED FROM   DBA_SQL_PLAN_BASELINES WHERE  SQL_TEXT LIKE '%MERGE%';

 

set serveroutput on

 

DECLARE

  v_dropped_plans number;

BEGIN

  v_dropped_plans := DBMS_SPM.DROP_SQL_PLAN_BASELINE (

     sql_handle => 'SQL_3ad68510622ed12d'

);

  DBMS_OUTPUT.PUT_LINE('dropped ' || v_dropped_plans || ' plans');

END;

/

 

dropped 1 plans

PL/SQL procedure successfully completed.

 

2.4.2 Find if there is a Plan Baseline for a given SQL_ID

 

Unfortunately, there is no easy way to get the SQL_ID from DBA_SQL_PLAN_BASELINES, we have to use also other Views.

 

From an SQL_ID found in V$SQL

 

SELECT s.sql_id , b.sql_handle, b.plan_name, s.child_number, s.plan_hash_value, s.executions

 FROM v$sql s, dba_sql_plan_baselines b

 WHERE s.exact_matching_signature = b.signature(+) AND s.sql_plan_baseline = b.plan_name(+)

             AND s.sql_id='d787swkmh37kg' ;

 

From an SQL_ID found in AWR History

 

-- From AWR

SELECT * -- sql_handle, plan_name

 FROM dba_sql_plan_baselines

 WHERE signature IN (

   SELECT force_matching_signature FROM dba_hist_sqlstat s, dba_hist_snapshot sn

   WHERE sql_id='d787swkmh37kg' and s.snap_id=sn.snap_id

        AND begin_interval_time >= TO_DATE('12/11/2015 08:30:00','DD/MM/YYYY HH24:MI:SS')

        AND begin_interval_time <  TO_DATE('12/11/2015 22:30:00','DD/MM/YYYY HH24:MI:SS')

 )

 

So back to :

1] Outlines


They’ll fix the execution plan !!

1.1 Create Outline from a Good In-Memory Execution Plan

2 plans : we have to manage to get the correct one, then grab it :

DAY
SQL_ID
PLAN_HV
MODULE
BG(M)
DK(K)
CPU(s)
ELAPSED(min)
05 29
4m9p7qndv97gm
2852960567
SQL*Plus
4,76
27,06
35,42
0,72
06 07
4m9p7qndv97gm
250938196
SQL*Plus
6039,75
26,69
18143,84
297,38

1. Get Hash_Value

select first_load_time,sql_id, plan_hash_value, HASH_VALUE, CHILD_NUMBER from v$sql where sql_id = '4m9p7qndv97gm'

FIRST_LOAD_TIME
SQL_ID
PLAN_HASH_VALUE
HASH_VALUE
CHILD_NUMBER
OUTLINE_CATEGORY
2012-06-07/15:25:40
4m9p7qndv97gm
2852960567
464821747
0

2. Create the Outline


BEGIN
  DBMS_OUTLN.create_outline(
    hash_value    => 464821747,
    child_number  => 0,
    category      => 'DEFAULT');
END;
/
PL/SQL procedure successfully completed.

SQL> set pages 5000 lines 150
SQL> select owner , NAME , CATEGORY, USED from dba_outlines ;

OWNER                          NAME                           CATEGORY                       USED
------------------------------ ------------------------------ ------------------------------ ------
APP                            SYS_OUTLINE_12060715262630702  DEFAULT                        UNUSED


3. Run SQL and Check


SQL> set pages 5000 lines 150
SQL> select owner , NAME , CATEGORY, USED from dba_outlines ;

OWNER                          NAME                           CATEGORY                       USED
------------------------------ ------------------------------ ------------------------------ ------
APP                            SYS_OUTLINE_12060715262630702  DEFAULT                        USED


1.2 Create Outline with a Wrong In-Memory Execution Plan

Here is a process to create an Outline with a correct Execution Plan got in another instance :
user USR01, sql_id = 5ytw413vjd7uj phv = 2662463244

1. Prerequisite

Find the old Hash_value

SQL> select first_load_time,sql_id, plan_hash_value, HASH_VALUE, CHILD_NUMBER from v$sql where sql_id = '5ytw413vjd7uj' ;

FIRST_LOAD_TIME     SQL_ID        PLAN_HASH_VALUE HASH_VALUE CHILD_NUMBER
------------------- ------------- --------------- ---------- ------------
2010-05-12/09:20:54 5ytw413vjd7uj      2662463244 4145454929            0

2. Create Outline from in-memory Wrong Plan

Connect as SYS, and use the Hash_Value :

BEGIN
  DBMS_OUTLN.create_outline(
    hash_value    => 4145454929,
    child_number  => 0,
    category      => 'USR01_OUTLN');
END;
/

PL/SQL procedure successfully completed.

SQL> select owner , NAME , CATEGORY, USED from dba_outlines ;

OWNER      NAME                                               CATEGORY                       USED
---------- -------------------------------------------------- ------------------------------ ------
USR01        SYS_OUTLINE_10051209231521301                      USR01_OUTLN                      UNUSED

SQL> grant CREATE ANY OUTLINE to huo ;
Grant succeeded.


3. Create Outline with Correct Exec Plan

Connect as SYS, and use the Hints found with "explain plan for" in another environment for example.

SQL> conn huo/huo
Connected.

CREATE outline PRIV_OUTLN_001 ON
SELECT
  /*+
      BEGIN_OUTLINE_DATA
      SWAP_JOIN_INPUTS(@"SEL$F5BB74E1_2" "B"@"SEL$F5BB74E1_2")
      SWAP_JOIN_INPUTS(@"SEL$F5BB74E1_1" "Y"@"SEL$1")
      SWAP_JOIN_INPUTS(@"SEL$F5BB74E1_1" "B"@"SEL$1")
      USE_HASH(@"SEL$F5BB74E1_2" "Y"@"SEL$F5BB74E1_2")
      USE_HASH(@"SEL$F5BB74E1_2" "HHRV7_ZY3B"@"SEL$F5BB74E1_2")
      USE_HASH(@"SEL$F5BB74E1_2" "B"@"SEL$F5BB74E1_2")
      USE_HASH(@"SEL$F5BB74E1_1" "Y"@"SEL$1")
      USE_HASH(@"SEL$F5BB74E1_1" "B"@"SEL$1")
      USE_MERGE(@"SEL$F5BB74E1_1" "U"@"SEL$1")
      LEADING(@"SEL$F5BB74E1_2" "U"@"SEL$F5BB74E1_2" "B"@"SEL$F5BB74E1_2"
              "HHRV7_ZY3B"@"SEL$F5BB74E1_2" "Y"@"SEL$F5BB74E1_2")
      LEADING(@"SEL$F5BB74E1_1" "HHRV7_ZY3B"@"SEL$2" "U"@"SEL$1" "B"@"SEL$1" "Y"@"SEL$1")
      INDEX_FFS(@"SEL$F5BB74E1_2" "Y"@"SEL$F5BB74E1_2" ("HHRV7_ZY00"."SOCDOS"
              "HHRV7_ZY00"."NUDOSS" "HHRV7_ZY00"."SOCCLE" "HHRV7_ZY00"."MATCLE"))
      FULL(@"SEL$F5BB74E1_2" "HHRV7_ZY3B"@"SEL$F5BB74E1_2")
      FULL(@"SEL$F5BB74E1_2" "B"@"SEL$F5BB74E1_2")
      FULL(@"SEL$F5BB74E1_2" "U"@"SEL$F5BB74E1_2")
      INDEX_FFS(@"SEL$F5BB74E1_1" "Y"@"SEL$1" ("HHRV7_ZY00"."SOCDOS" "HHRV7_ZY00"."NUDOSS"
              "HHRV7_ZY00"."SOCCLE" "HHRV7_ZY00"."MATCLE"))
      FULL(@"SEL$F5BB74E1_1" "B"@"SEL$1")
      FULL(@"SEL$F5BB74E1_1" "U"@"SEL$1")
      FULL(@"SEL$F5BB74E1_1" "HHRV7_ZY3B"@"SEL$2")
      MERGE(@"SEL$2")
      OUTLINE(@"SEL$F5BB74E1")
      OUTLINE(@"SEL$2")
      OUTLINE(@"SEL$1")
      OUTLINE_LEAF(@"SEL$F5BB74E1_2")
      USE_CONCAT(@"SEL$F5BB74E1" 8)
      OUTLINE_LEAF(@"SEL$F5BB74E1_1")
      MERGE(@"SEL$2")
      OUTLINE_LEAF(@"SEL$F5BB74E1")
      ALL_ROWS
      OPT_PARAM('_optimizer_transitivity_retain' 'false')
      OPT_PARAM('query_rewrite_enabled' 'false')
      OPT_PARAM('_b_tree_bitmap_plans' 'false')
      OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
      IGNORE_OPTIM_EMBEDDED_HINTS
      END_OUTLINE_DATA
  */
u.uo_id, TRIM (y.matcle) AS matcle_resp_uo
  FROM hhr_uo_public_tmp u,
       hhrv7_ze0b b,
       (SELECT *
          FROM hhrv7_zy3b
         WHERE SYSDATE BETWEEN dtef00 AND dten00) x,
       hhrv7_zy00 y
 WHERE u.nudoss = b.nudoss(+)
   AND (   (b.idps00 = x.idps00 AND x.nudoss = y.nudoss)
        OR (b.matcle = y.matcle)
       )
/
Outline created.

SQL> conn / as sysdba
Connected.
SQL> select name,owner,category from dba_outlines ;

NAME                                               OWNER      CATEGORY
-------------------------------------------------- ---------- ------------------------------
SYS_OUTLINE_10051209231521301                      USR01        USR01_OUTLN
PRIV_OUTLN_001                                     USR01        DEFAULT


4. Swith the Outlines OK <-> KO

UPDATE OUTLN.OL$HINTS
SET OL_NAME=DECODE(OL_NAME,'PRIV_OUTLN_001','SYS_OUTLINE_10051209231521301','SYS_OUTLINE_10051209231521301','PRIV_OUTLN_001')
WHERE OL_NAME IN ('SYS_OUTLINE_10051209231521301','PRIV_OUTLN_001');
UPDATE OUTLN.OL$NODES
SET OL_NAME=DECODE(OL_NAME,'PRIV_OUTLN_001','SYS_OUTLINE_10051209231521301','SYS_OUTLINE_10051209231521301','PRIV_OUTLN_001')
WHERE OL_NAME IN ('SYS_OUTLINE_10051209231521301','PRIV_OUTLN_001');
commit ;

SQL> select owner , NAME , CATEGORY, USED from dba_outlines ;

OWNER      NAME                                               CATEGORY                       USED
---------- -------------------------------------------------- ------------------------------ ------
USR01        SYS_OUTLINE_10051209231521301                      USR01_OUTLN                      UNUSED


5. Some cleanup and post actions

SQL> drop outline PRIV_OUTLN_001 ;
Outline dropped.

Session should be altered to be able to use the Outline :
Example modify trigger system.db_logon :

if ( user in ('USR01') ) then
execute immediate 'alter session set use_stored_outlines=USR01_OUTLN';
end if;


Or change category to DEFAULT :


SQL> alter outline SYS_OUTLINE_14042511213537301 change category to "DEFAULT" ;
Outline altered.


6. Run SQL

SQL> select owner , NAME , CATEGORY, USED from dba_outlines ;

OWNER      NAME                                               CATEGORY                       USED
---------- -------------------------------------------------- ------------------------------ ------
USR01        SYS_OUTLINE_10051209231521301                      USR01_OUTLN                      USED