1. Evolving Execution Plans - example
Evolving Execution Plans
1. Check what SQL Plan Baselines that exists in the database:
SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN,ENABLED, ACCEPTED
FROM DBA_SQL_PLAN_BASELINES;
no rows selected
SQL> show parameter OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES
NAME TYPE VALUE
------------------------------------ ----------- ----------
optimizer_capture_sql_plan_baselines boolean FALSE
2. Turn on capture:
SQL> alter system set OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES=true;
3. The SQL statement that we are going to work with in this example:
select /* bsln */ d.department_id, count(e.employee_id)
from hr.employees e, hr.departments d
where e.department_id=d.department_id
and d.department_id=(select department_id from hr.employees where employee_id=180)
group by d.department_id;
DEPARTMENT_ID COUNT(E.EMPLOYEE_ID)
------------- --------------------
50 46
Execute the statement again, so it is captured by the SQL plan management. (This only captures repeatable statements, remember?)
Check and confirm the statement was captured:
col sql_handle for A20
col sql_text for A20 word_wrapped
col plan_name for A30
col origin for A12
col enabled for A3
2. Evolving Execution Plans - example
col accepted for A3
col fixed for A3
set linesize 150
SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME,
ORIGIN, ENABLED, ACCEPTED, FIXED
FROM DBA_SQL_PLAN_BASELINES
WHERE lower(SQL_TEXT) LIKE '%bsln%';
SQL_HANDLE SQL_TEXT PLAN_NAME ORIGIN ENA ACC FIX
-------------------- -------------------- ------------------------------ ------------ --- ---
SQL_d32392b2e4557ee0 select /* bsln */ SQL_PLAN_d68wkqbk5azr09158ac75 AUTO-CAPTURE YES YES NO
d.department_id,
count(e.employee_id)
from hr.employees e,
hr.
Get the execution plan:
SQL> @xplan aubf20ky0r3p1 1
SQL_ID CHILD_NUMBER PLAN_HASH_VALUE ELAPSED CPU EXEC LIO PIO NUM_ROWS
--------------- -------------- --------------- ---------- ---------- ---------- ---------- ---------- ----------
aubf20ky0r3p1 0 4023081993 .027 .022 1 216 0 1
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
SQL_ID aubf20ky0r3p1, child number 0
-------------------------------------
select /* bsln */ d.department_id, count(e.employee_id) from
hr.employees e, hr.departments d where e.department_id=d.department_id
and d.department_id=(select department_id from hr.employees where
employee_id=180) group by d.department_id
Plan hash value: 4023081993
----------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows | Cost (%CPU)| E-Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | 5 (100)| |
| 1 | HASH GROUP BY | | 7 | 5 (20)| 00:00:01 |
|* 2 | TABLE ACCESS FULL | EMPLOYEES | 10 | 3 (0)| 00:00:01 |
3. Evolving Execution Plans - example
| 3 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | 0 (0)| |
----------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$F7859CDE
2 - SEL$F7859CDE / E@SEL$1
3 - SEL$2 / EMPLOYEES@SEL$2
4 - SEL$2 / EMPLOYEES@SEL$2
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('18.1.0')
DB_VERSION('18.1.0')
ALL_ROWS
OUTLINE_LEAF(@"SEL$2")
OUTLINE_LEAF(@"SEL$F7859CDE")
ELIMINATE_JOIN(@"SEL$1" "D"@"SEL$1")
OUTLINE(@"SEL$1")
FULL(@"SEL$F7859CDE" "E"@"SEL$1")
USE_HASH_AGGREGATION(@"SEL$F7859CDE")
PUSH_SUBQ(@"SEL$2")
INDEX_RS_ASC(@"SEL$2" "EMPLOYEES"@"SEL$2" ("EMPLOYEES"."EMPLOYEE_ID"))
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(("E"."DEPARTMENT_ID" IS NOT NULL AND "E"."DEPARTMENT_ID"=))
4 - access("EMPLOYEE_ID"=180)
Note
-----
- Warning: basic plan statistics not available. These are only collected when:
* hint 'gather_plan_statistics' is used for the statement or
* parameter 'statistics_level' is set to 'ALL', at session or system level
4. Evolving Execution Plans - example
4. Let's create an index:
create index hr.emp_dept_ix on hr.employees(employee_id,department_id);
Run the SQL statement again:
select /* bsln */ d.department_id, count(e.employee_id)
from hr.employees e, hr.departments d
where e.department_id=d.department_id
and d.department_id=(select department_id from hr.employees where employee_id=180)
group by d.department_id;
Check the baselines:
SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME,
2 ORIGIN, ENABLED, ACCEPTED, FIXED
3 FROM DBA_SQL_PLAN_BASELINES
4 WHERE lower(SQL_TEXT) LIKE '%bsln%';
SQL_HANDLE SQL_TEXT PLAN_NAME ORIGIN ENA ACC FIX
-------------------- -------------------- ------------------------------ ------------ --- --- ---
SQL_d32392b2e4557ee0 select /* bsln */ SQL_PLAN_d68wkqbk5azr09158ac75 AUTO-CAPTURE YES YES NO
d.department_id,
count(e.employee_id)
from hr.employees e,
hr.
SQL_d32392b2e4557ee0 select /* bsln */ SQL_PLAN_d68wkqbk5azr09ecdb1d7 AUTO-CAPTURE YES NO NO
d.department_id,
count(e.employee_id)
from hr.employees e,
hr.
There are 2 execution plans now.
The SQL_HANDLE is the same, but the plan name is different: SQL_PLAN_d68wkqbk5azr09158ac75, SQL_PLAN_d68wkqbk5azr09ecdb1d7
5. Evolving Execution Plans - example
Notice that SQL_PLAN_d68wkqbk5azr09ecdb1d7 is enabled, but not accepted.
Let's evolve the second plan:
a. create the evolve task:
set serveroutput on
declare
l_return varchar2(30000);
begin
l_return := dbms_spm.create_evolve_task(sql_handle
=>'SQL_d32392b2e4557ee0');
dbms_output.put_line('Task Name: ' || l_return);
end;
/
Task Name: TASK_21
PL/SQL procedure successfully completed.
b. execute the evolve task:
set serveroutput on
declare
l_return varchar2(30000);
begin
l_return :=dbms_spm.execute_evolve_task(task_name
=>'TASK_21');
dbms_output.put_line('Execution Name: ' || l_return);
end;
/
Execution Name: EXEC_271
PL/SQL procedure successfully completed.
c. report on the evolve task
set long 1000000
set pagesize 1000
set longchunksize 100
6. Evolving Execution Plans - example
set linesize 200
select dbms_spm.report_evolve_task(task_name=>'TASK_21',execution_name=>'EXEC_271') as report
from dual;
REPORT
----------------------------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
---------------------------------------------------------------------------------------------
Task Information:
---------------------------------------------
Task Name : TASK_21
Task Owner : SYS
Execution Name : EXEC_271
Execution Type : SPM EVOLVE
Scope : COMPREHENSIVE
Status : COMPLETED
Started : 11/28/2018 08:42:59
Finished : 11/28/2018 08:43:00
Last Updated : 11/28/2018 08:43:00
Global Time Limit : 2147483646
Per-Plan Time Limit : UNUSED
Number of Errors : 0
---------------------------------------------------------------------------------------------
SUMMARY SECTION
---------------------------------------------------------------------------------------------
Number of plans processed : 2
Number of findings : 2
Number of recommendations : 2
Number of errors : 0
---------------------------------------------------------------------------------------------
DETAILS SECTION
---------------------------------------------------------------------------------------------
Object ID : 2
Test Plan Name : SQL_PLAN_d68wkqbk5azr09ecdb1d7
Base Plan Name : SQL_PLAN_d68wkqbk5azr09158ac75
SQL Handle : SQL_d32392b2e4557ee0
Parsing Schema : SYS
Test Plan Creator : SYS
SQL Text : select /* bsln */ d.department_id, count(e.employee_id)
from hr.employees e, hr.departments d where
7. Evolving Execution Plans - example
e.department_id=d.department_id and d.department_id=(select
department_id from hr.employees where employee_id=180)
group by d.department_id
Execution Statistics:
-----------------------------
Base Plan Test Plan
---------------------------- ----------------------------
Elapsed Time (s): .000024 .000021
CPU Time (s): .000029 .000015
Buffer Gets: 0 0
Optimizer Cost: 5 3
Disk Reads: 0 0
Direct Writes: 0 0
Rows Processed: 0 0
Executions: 10 10
FINDINGS SECTION
---------------------------------------------------------------------------------------------
Findings (1):
-----------------------------
1. The plan was verified in 0.07500 seconds. It passed the benefit criterion
because its verified performance was 4.48035 times better than that of the
baseline plan.
Recommendation:
-----------------------------
Consider accepting the plan. Execute
dbms_spm.accept_sql_plan_baseline(task_name => 'TASK_21', object_id => 2,
task_owner => 'SYS');
EXPLAIN PLANS SECTION
---------------------------------------------------------------------------------------------
Baseline Plan
-----------------------------
Plan Id : 101
Plan Hash Value : 2438507637
------------------------------------------------------------------------------------------
8. Evolving Execution Plans - example
| Id | Operation | Name | Rows | Bytes | Cost | Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 21 | 5 | 00:00:01 |
| 1 | HASH GROUP BY | | 7 | 21 | 5 | 00:00:01 |
| * 2 | TABLE ACCESS FULL | EMPLOYEES | 10 | 30 | 3 | 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 1 | 7 | 1 | 00:00:01 |
| * 4 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 | 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 2 - filter("E"."DEPARTMENT_ID" IS NOT NULL AND "E"."DEPARTMENT_ID"= (SELECT /*+ PUSH_SUBQ INDEX_RS
_ASC ("EMPLOYEES" "EMP_EMP_ID_PK") */ "DEPARTMENT_ID" FROM "HR"."EMPLOYEES"
"EMPLOYEES" WHERE "EMPLOYEE_ID"=180))
* 4 - access("EMPLOYEE_ID"=180)
Test Plan
-----------------------------
Plan Id : 102
Plan Hash Value : 2664280535
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 21 | 3 | 00:00:01 |
| 1 | HASH GROUP BY | | 7 | 21 | 3 | 00:00:01 |
| * 2 | INDEX SKIP SCAN | EMP_DEPT_IX | 10 | 30 | 1 | 00:00:01 |
| * 3 | INDEX RANGE SCAN | EMP_DEPT_IX | 1 | 7 | 1 | 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 2 - access("E"."DEPARTMENT_ID"= (SELECT /*+ PUSH_SUBQ INDEX ("EMPLOYEES" "EMP_DEPT_IX") */ "DEPART
MENT_ID" FROM "HR"."EMPLOYEES" "EMPLOYEES" WHERE "EMPLOYEE_ID"=180))
* 2 - filter("E"."DEPARTMENT_ID" IS NOT NULL AND "E"."DEPARTMENT_ID"= (SELECT /*+ PUSH_SUBQ INDEX ("
EMPLOYEES" "EMP_DEPT_IX") */ "DEPARTMENT_ID" FROM "HR"."EMPLOYEES" "EMPLOYEES"
WHERE "EMPLOYEE_ID"=180))
* 3 - access("EMPLOYEE_ID"=180)
---------------------------------------------------------------------------------------------
Object ID : 3
Test Plan Name : SQL_PLAN_d68wkqbk5azr09ecdb1d7
9. Evolving Execution Plans - example
Base Plan Name : SQL_PLAN_d68wkqbk5azr09158ac75
SQL Handle : SQL_d32392b2e4557ee0
Parsing Schema : SYS
Test Plan Creator : SYS
SQL Text : select /* bsln */ d.department_id, count(e.employee_id)
from hr.employees e, hr.departments d where
e.department_id=d.department_id and d.department_id=(select
department_id from hr.employees where employee_id=180)
group by d.department_id
Execution Statistics:
-----------------------------
Base Plan Test Plan
---------------------------- ----------------------------
Elapsed Time (s): .00002 .000018
CPU Time (s): .00003 .000023
Buffer Gets: 0 0
Optimizer Cost: 5 3
Disk Reads: 0 0
Direct Writes: 0 0
Rows Processed: 0 0
Executions: 10 10
FINDINGS SECTION
---------------------------------------------------------------------------------------------
Findings (1):
-----------------------------
1. The plan was verified in 0.04000 seconds. It passed the benefit criterion
because its verified performance was 4.46286 times better than that of the
baseline plan.
Recommendation:
-----------------------------
Consider accepting the plan. Execute
dbms_spm.accept_sql_plan_baseline(task_name => 'TASK_21', object_id => 3,
task_owner => 'SYS');
EXPLAIN PLANS SECTION
---------------------------------------------------------------------------------------------
10. Evolving Execution Plans - example
Baseline Plan
-----------------------------
Plan Id : 103
Plan Hash Value : 2438507637
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 21 | 5 | 00:00:01 |
| 1 | HASH GROUP BY | | 7 | 21 | 5 | 00:00:01 |
| * 2 | TABLE ACCESS FULL | EMPLOYEES | 10 | 30 | 3 | 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 1 | 7 | 1 | 00:00:01 |
| * 4 | INDEX UNIQUE SCAN | EMP_EMP_ID_PK | 1 | | 0 | 00:00:01 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 2 - filter("E"."DEPARTMENT_ID" IS NOT NULL AND "E"."DEPARTMENT_ID"= (SELECT /*+ PUSH_SUBQ INDEX_RS
_ASC ("EMPLOYEES" "EMP_EMP_ID_PK") */ "DEPARTMENT_ID" FROM "HR"."EMPLOYEES"
"EMPLOYEES" WHERE "EMPLOYEE_ID"=180))
* 4 - access("EMPLOYEE_ID"=180)
Test Plan
-----------------------------
Plan Id : 104
Plan Hash Value : 2664280535
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 21 | 3 | 00:00:01 |
| 1 | HASH GROUP BY | | 7 | 21 | 3 | 00:00:01 |
| * 2 | INDEX SKIP SCAN | EMP_DEPT_IX | 10 | 30 | 1 | 00:00:01 |
| * 3 | INDEX RANGE SCAN | EMP_DEPT_IX | 1 | 7 | 1 | 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 2 - access("E"."DEPARTMENT_ID"= (SELECT /*+ PUSH_SUBQ INDEX ("EMPLOYEES" "EMP_DEPT_IX") */ "DEPART
MENT_ID" FROM "HR"."EMPLOYEES" "EMPLOYEES" WHERE "EMPLOYEE_ID"=180))
* 2 - filter("E"."DEPARTMENT_ID" IS NOT NULL AND "E"."DEPARTMENT_ID"= (SELECT /*+ PUSH_SUBQ INDEX ("
EMPLOYEES" "EMP_DEPT_IX") */ "DEPARTMENT_ID" FROM "HR"."EMPLOYEES" "EMPLOYEES"
11. Evolving Execution Plans - example
WHERE "EMPLOYEE_ID"=180))
* 3 - access("EMPLOYEE_ID"=180)
...
---------------------------------------------------------------------------------------------
d. implement the evolve task
set serveroutput on
declare
l_return number;
begin
l_return:=dbms_spm.implement_evolve_task
(task_name => 'TASK_21');
dbms_output.put_line('Accepted Plans: ' || l_return);
end;
/
Accepted Plans: 2
PL/SQL procedure successfully completed.
Verify that both plans are accepted now:
SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME,
2 ORIGIN, ENABLED, ACCEPTED, FIXED
3 FROM DBA_SQL_PLAN_BASELINES
4 WHERE lower(SQL_TEXT) LIKE '%bsln%';
SQL_HANDLE SQL_TEXT PLAN_NAME ORIGIN ENA ACC FIX
-------------------- -------------------- ------------------------------ ------------ --- --- ---
SQL_d32392b2e4557ee0 select /* bsln */ SQL_PLAN_d68wkqbk5azr09158ac75 AUTO-CAPTURE YES YES NO
d.department_id,
count(e.employee_id)
from hr.employees e,
hr.
SQL_d32392b2e4557ee0 select /* bsln */ SQL_PLAN_d68wkqbk5azr09ecdb1d7 AUTO-CAPTURE YES YES NO
d.department_id,