A couple of years ago I set myself a best practice goal of preferring SPM baselines over SQL-Profiles. I must recognize that I failed to achieve this goal. Fortunately as of Oracle 12cR2 it becomes possible to load SPM baselined plans directly from AWR tables. This is why I am now unexcused to do not operate the switch.
Let’s see first how we can load SPM plans using AWR historical tables
Setting the Scenes
create table t_acs(n1 number, n2 number); BEGIN for j in 1..1200150 loop if j = 1 then insert into t_acs values (j, 1); elsif j>1 and j<=101 then insert into t_acs values(j, 100); elsif j>101 and j<=1101 then insert into t_acs values (j, 1000); elsif j>10001 and j<= 110001 then insert into t_acs values(j,10000); else insert into t_acs values(j, 1000000); end if; end loop; commit; END; / create index t_acs_i1 on t_acs(n2); BEGIN dbms_stats.gather_table_stats (user ,'t_acs' ,method_opt => 'for all columns size skewonly' ,cascade => true ,estimate_percent => dbms_stats.auto_sample_size ); END; / exec dbms_workload_repository.create_snapshot; var ln2 number; exec :ln2 := 100 select count(1) from t_acs where n2 = :ln2; exec :ln2 := 1e6 select count(1) from t_acs where n2 = :ln2; select count(1) from t_acs where n2 = :ln2; exec :ln2 := 100 select count(1) from t_acs where n2 = :ln2; exec dbms_workload_repository.create_snapshot;
If you copy and past the above SQL code into a SQL PLUS session and issue the following select you should find that you have already two bind aware cursors:
select sql_id ,child_number ,is_bind_sensitive ,is_bind_aware ,executions from v$sql where sql_id = 'f2pmwazy1rnfd' and is_shareable = 'Y'; SQL_ID CHILD_NUMBER I I EXECUTIONS ------------- ------------ - - ---------- f2pmwazy1rnfd 1 Y Y 1 f2pmwazy1rnfd 2 Y Y 1
The bind awareness property of the above cursor has nothing to do with the bottom line of this article. It is here just because I will use the same model in my next article where this time this particular property becomes necessary.
If I would have decided to create a SQL profile over the above cursor I would have then opted for Carlos Sierra coe_xfr_sql_profile.sql script as shown below:
SQL> @coe_xfr_sql_profile.sql Parameter 1: SQL_ID (required) Enter value for 1: f2pmwazy1rnfd PLAN_HASH_VALUE AVG_ET_SECS --------------- ----------- 535703726 ,054 1882749816 ,085 Parameter 2: PLAN_HASH_VALUE (required) Enter value for 2: 1882749816 Values passed: ~~~~~~~~~~~~~ SQL_ID : "f2pmwazy1rnfd" PLAN_HASH_VALUE: "1882749816" Execute coe_xfr_sql_profile_f2pmwazy1rnfd_1882749816.sql on TARGET system in order to create a custom SQL Profile with plan 1882749816 linked to adjusted sql_text. SQL>@coe_xfr_sql_profile_f2pmwazy1rnfd_1882749816.sql ... manual custom SQL Profile has been created COE_XFR_SQL_PROFILE_f2pmwazy1rnfd_1882749816 completed
As such the next time I will run this query it will use the fixed SQL Profile as shown below:
SQL> select count(1) from t_acs where n2 = :ln2; SQL> select * from table(dbms_xplan.display_cursor); Plan hash value: 1882749816 ------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | ------------------------------------------------------ | 0 | SELECT STATEMENT | | | | | 1 | SORT AGGREGATE | | 1 | 3 | |* 2 | INDEX RANGE SCAN| T_ACS_I1 | 100 | 300 | ------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("N2"=:LN2) Note ----- - SQL profile coe_f2pmwazy1rnfd_1882749816 used for this statement
However until the arrival of 12cR2 it was impossible to load a SPM plan baseline for the above cursor using corresponding AWR historical execution plan. Hopefully it is now possible. This is below how to capture SPM plan from AWR:
SQL>@LoadSPMfromAwr.sql Listing latest AWR snapshots ... SNAP_ID END_INTERVAL_TIME ---------- --------------------------- 14 08/03/17 13:20:09,251000000 15 08/03/17 14:00:13,233000000 16 08/03/17 15:07:46,465000000 17 09/03/17 01:13:41,092000000 18 09/03/17 12:11:26,748000000 19 10/03/17 01:07:36,836000000 20 10/03/17 10:08:54,214000000 21 10/03/17 12:35:26,590000000 22 11/03/17 01:04:40,947000000 23 12/03/17 12:41:35,578000000 24 12/03/17 15:03:55,730000000 25 13/03/17 02:21:01,517000000 26 13/03/17 12:53:22,204000000 27 13/03/17 15:43:46,522000000 28 14/03/17 13:13:07,716000000 29 15/03/17 12:55:54,089000000 30 16/03/17 12:59:39,201000000 31 17/03/17 02:09:14,047000000 32 17/03/17 10:38:33,520000000 33 17/03/17 12:50:59,072000000 20 rows selected. Enter begin snapshot id: 14 Enter end snapshot id: 27 Enter value for sql_filter: sql_text like ''select count(1) from t_acs%'' SQL> select plan_name ,origin from dba_sql_plan_baselines; PLAN_NAME ORIGIN ---------------------------------------- --------------------- SQL_PLAN_fn4mhg52jx5z125348c47 MANUAL-LOAD-FROM-AWR SQL_PLAN_fn4mhg52jx5z13069e6f9 MANUAL-LOAD-FROM-AWR SQL> select count(1) from t_acs where n2 = :ln2; SQL> select * from table(dbms_xplan.display_cursor); SQL_ID f2pmwazy1rnfd, child number 1 ------------------------------------- select count(1) from t_acs where n2 = :ln2 Plan hash value: 1882749816 ------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | ------------------------------------------------------ | 0 | SELECT STATEMENT | | | | | 1 | SORT AGGREGATE | | 1 | 3 | |* 2 | INDEX RANGE SCAN| T_ACS_I1 | 100 | 300 | ------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("N2"=:LN2) Note ----- - SQL profile coe_f2pmwazy1rnfd_1882749816 used for this statement - SQL plan baseline SQL_PLAN_fn4mhg52jx5z125348c47 used for this statement
You have to choose the snap interval that includes historical details of your sql_id
Here’s below the content of the script I used to capture SPM plan from AWR
PROMPT Listing latest AWR snapshots ... SELECT snap_id, end_interval_time FROM dba_hist_snapshot WHERE end_interval_time > SYSDATE - 30 ORDER BY end_interval_time; ACCEPT bsnapid NUMBER PROMPT "Enter begin snapshot id: " ACCEPT esnapid NUMBER PROMPT "Enter end snapshot id: " SET TERMOUT OFF PAGESIZE 0 HEADING OFF LINESIZE 1000 TRIMSPOOL ON TRIMOUT ON TAB OFF declare rs pls_integer; begin rs := dbms_spm.load_plans_from_awr('&bsnapid', '&esnapid', '&sql_filter'); end; / SET TERMOUT ON PAGESIZE 5000 HEADING ON
