Oracle性能优化(二)SQL Plan Management

1. SPM相关参数
optimizer_capture_sql_plan_baselines
optimizer_use_sql_plan_baselines
create_stored_outline
use_stored_outlines

2. 与profile和outline相比,更加灵活的控制手段
(1)可以有很多的计划被保存下来,只有"ENABLED"并且"ACCEPTED"的执行计划才可以被选择。
(2)允许有多个"ACCEPTED"的执行计划,根据实际情况进行选择。
(3)可以用手工或者自动的方式,把执行计划演化(evolve)为"ACCEPTED"。 还可以控制只让性能更好的计划被接受。
(4)允许设置"FIXED"的计划。这样其他的计划将不会被选择。

3. SPM的控制方式
(1)Enabled (控制活动):

  • YES (活动的,但不一定会被使用)
  • NO (可以理解为被标记删除)
    (2)Accepted(控制使用):
  • YES (只有 “Enabled” 并且“Accepted” 的计划才会被选择使用)
  • NO (如果是“Enabled” 那么只有被evolve成“Accepted”才有可能被执行)
    (3)Fixed(控制优先级):
  • YES (如果是“Enabled”并且“Accepted”,会优先选择这个计划,这个计划会被视为不需要改变的)
  • NO (普通的计划,无需优先)
    (4)Reproduced(有效性):
  • YES (优化器可以使用这个计划)
  • NO (计划无效,比如索引被删除)

4. SPM如何捕捉(加载)执行计划

  • 自动捕获
    (1)首先把OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES设置成TRUE。
    (2)从这个时刻开始,所有执行两次以上的SQL语句会被观测,执行计划会进入Plan History。有个别例外的,参见note 788853.1。
    (3)生成的第一个执行计划被标记为ENABLED并且是ACCEPTED,后续的执行计划会被标记为ENABLED但不是ACCEPTED。
    (4)这时把OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES设置会FALSE,新的语句将不会创建Baseline。
    (5)需要注意的是,即使关闭了自动捕捉,针对存在baseline的SQL,由于ACS(自适应游标共享)的作用,仍旧会有新的PLAN生成,新的Plan仍会进入Plan History,标记为ENABLED但不是ACCEPTED。
  • 批量导入
    (1)从 SQL Tuning Set STS 导入:DBMS_SPM.LOAD_PLANS_FROM_SQLSET
    (2)从Cursor Cache中装载:DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE
    (3)从Stored Outlines中导入: DBMS_SPM.MIGRATE_STORED_OUTLINE
    (4)从内存中存在的计划中导入:DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE;
    (5)从staging table表中导入:dbms_spm.create_stgtab_baseline;
    (6)通过staging table从另外一个系统中移植:
    DBMS_SPM.CREATE_STGTAB_BASELINE
    DBMS_SPM.PACK_STGTAB_BASELINE
    DBMS_SPM.UNPACK_STGTAB_BASELINE

使用正确的SQL PLAN BASELINE

SQL> CREATE TABLE BASELINE_TEST1 AS SELECT * FROM DBA_OBJECTS;

SQL> CREATE TABLE BASELINE_TEST2 AS SELECT * FROM DBA_OBJECTS WHERE ROWNUM<100;

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS (OWNNAME => ‘sys’, TABNAME => ‘BASELINE_TEST1’);

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS (OWNNAME => ‘sys’, TABNAME => ‘BASELINE_TEST2’);

SQL> select * from dba_sql_plan_baselines;

no rows selected

SQL> alter system set optimizer_capture_sql_plan_baselines=TRUE;

SQL> select count(*) from BASELINE_TEST1 where object_id in (select object_id from BASELINE_TEST2);

COUNT (*)
99

SQL> select sql_handle,sql_text,plan_name,creator,last_modified,last_executed,last_verified from dba_sql_plan_baselines;

no rows selected

SQL> select count(*) from BASELINE_TEST1 where object_id in (select object_id from BASELINE_TEST2);

COUNT (*)
99

SQL> select sql_handle,sql_text,plan_name,creator,last_modified,last_executed,last_verified,accepted from dba_sql_plan_baselines;

sql_handle sql_text plan_name creator last_modified last_executed last_verified accepted
SQL_579305a4a736ac60 select count(*) from BASELINE_TEST1 where object_id in (select object_id from BASELINE_TEST2) SQL_PLAN_5g4s5nkmmdb30ed4c7833 sys 20-MAR-2019 20-MAR-2019 (null) YES

SQL> alter system set optimizer_capture_sql_plan_baselines=FALSE;

SQL> select * from table(dbms_xplan.display_sql_plan_baseline(sql_handle =>‘SQL_579305a4a736ac60’));

SQL handle: SQL_579305a4a736ac60 SQL text: select count() from
baseline_test1 where object_id in (select
object_id from baseline_test2) Plan name: SQL_PLAN_5g4s5nkmmdb30ed4c7833 Plan id: 3981211699 Enabled:
YES Fixed: NO Accepted: YES Origin: AUTO-CAPTURE Plan
rows: From dictionary Plan hash value: 1308779663 | Id |
Operation | Name | Rows | Bytes | Cost (%CPU)|
Time | | 0 | SELECT STATEMENT | | 1 |
18 | 418 (1)| 00:00:01 | | 1 | SORT AGGREGATE |
| 1 | 18 | | | |
2 | HASH JOIN RIGHT
SEMI| | 99 | 1782 | 418 (1)| 00:00:01 | | 3 |
VIEW | VW_NSO_1 | 99 | 1287 | 2 (0)|
00:00:01 | | 4 | TABLE ACCESS FULL | BASELINE_TEST2 | 99 |
297 | 2 (0)| 00:00:01 | | 5 | TABLE ACCESS FULL |
BASELINE_TEST1 | 90924 | 443K| 416 (1)| 00:00:01 | Predicate
Information (identified by operation id):
2 - access(“OBJECT_ID”=“OBJECT_ID”)

SQL> create index index_baseline_test1 on baseline_test1(object_id);

SQL> exec dbms_stats.gather_table_stats (ownname =>‘sys’, tabname =>‘BASELINE_TEST1’ ,method_opt =>‘for all columns size 1’, cascade => true, no_invalidate =>false);

SQL> exec dbms_stats.gather_table_stats (ownname =>‘sys’, tabname =>‘BASELINE_TEST2’ ,method_opt =>‘for all columns size 1’, cascade => true, no_invalidate =>false);

SQL> select count(*) from BASELINE_TEST1 where object_id in (select object_id from BASELINE_TEST2);

SQL> select sql_handle,sql_text,plan_name,creator,last_modified,last_executed,last_verified,accepted from dba_sql_plan_baselines where sql_handle=‘SQL_579305a4a736ac60’;

sql_handle sql_text plan_name creator last_modified last_executed last_verified accepted
SQL_579305a4a736ac60 select count(*) from BASELINE_TEST1 where object_id in (select object_id from BASELINE_TEST2) SQL_PLAN_5g4s5nkmmdb30ed4c7833 sys 20-MAR-2019 20-MAR-2019 (null) NO
SQL_579305a4a736ac60 select count(*) from BASELINE_TEST1 where object_id in (select object_id from BASELINE_TEST2) SQL_PLAN_5g4s5nkmmdb30ed4c7833 sys 20-MAR-2019 20-MAR-2019 (null) YES

SQL> set serveroutput on;
SQL> declare
2 result_clob clob;
3 begin
4 result_clob:=dbms_spm.EVOLVE_SQL_PLAN_BASELINE(
5 sql_handle =>‘SQL_579305a4a736ac60’,
6 plan_name =>‘SQL_PLAN_5g4s5nkmmdb305e59f0e1’,
7 verify =>‘YES’,
8 commit =>‘YES’
9 );
10 dbms_output.put_line(result_clob);
11 end;
12 /

GENERAL INFORMATION
SECTION

Task Information:

Task Name : TASK_203

Task Owner : SYS
Execution Name : EXEC_169

Execution Type : SPM EVOLVE
Scope :
COMPREHENSIVE
Status : COMPLETED
Started
: 03/25/2019 06:46:47
Finished : 03/25/2019 06:46:47
Last
Updated : 03/25/2019 06:46:47
Global Time Limit : 2147483646

Per-Plan Time Limit : UNUSED
Number of Errors : 0

SUMMARY
SECTION

Number of plans processed : 1
Number of findings
: 2
Number of recommendations : 1
Number of errors : 0

DETAILS
SECTION

Object ID : 2

Test Plan Name : SQL_PLAN_5g4s5nkmmdb305e59f0e1

Base Plan Name : SQL_PLAN_5g4s5nkmmdb30ed4c7833

SQL Handle : SQL_579305a4a736ac60

Parsing Schema : SYS

Test Plan Creator : SYS

SQL Text : select count(*) from BASELINE_TEST1 where object_id in
(select object_id from BASELINE_TEST2)

Execution Statistics:
Base
Plan Test Plan

Elapsed Time (s):
.000671 .000435
CPU Time (s):
.000667 .000422
Buffer Gets:
153 21
Optimizer Cost:
418 59
Disk Reads:
0 0
Direct Writes:
0 0
Rows Processed:
0 0
Executions:
10 10

FINDINGS
SECTION

Findings (2):

1. The plan
was verified in 0.13000 seconds. It passed the benefit criterion
because
its verified performance was 7.20013 times better than that of the

baseline plan.
2.
The plan was automatically accepted.

Recommendation:

Consider accepting the plan.

EXPLAIN PLANS
SECTION

Baseline Plan
Plan Id
: 103
Plan Hash Value : 3981211699

| Id | Operation | Name | Rows | Bytes | Cost
| Time
|

| 0 | SELECT STATEMENT | | 1 | 18 | 418
| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 18 |
| |
| * 2 | HASH JOIN RIGHT SEMI | | 99 | 1782 |
418 | 00:00:01 |
| 3 | VIEW | VW_NSO_1 | 99 |
1287 | 2 | 00:00:01 |
| 4 | TABLE ACCESS FULL | BASELINE_TEST2 |
99 | 297 | 2 | 00:00:01 |
| 5 | TABLE ACCESS FULL | BASELINE_TEST1
| 91004 | 455020 | 416 | 00:00:01
|

Predicate Information (identified by operation
id):

* 2 -
access(“OBJECT_ID”=“OBJECT_ID”)

Test Plan

Plan
Id : 104
Plan Hash Value : 1582952673

| Id | Operation | Name | Rows |
Bytes | Cost | Time
|

| 0 | SELECT STATEMENT | | 1 |
18 | 59 | 00:00:01 |
| 1 | SORT AGGREGATE | |
1 | 18 | | |
| * 2 | HASH JOIN RIGHT SEMI |
| 99 | 1782 | 59 | 00:00:01 |
| 3 | VIEW | VW_NSO_1
| 99 | 1287 | 2 | 00:00:01 |
| 4 | TABLE ACCESS FULL |
BASELINE_TEST2 | 99 | 297 | 2 | 00:00:01 |
| 5 | INDEX FAST
FULL SCAN | INDEX_BASELINE_TEST1 | 91004 | 455020 | 56 | 00:00:01
|

Predicate Information (identified by operation
id):

* 2 -
access(“OBJECT_ID”=“OBJECT_ID”)

PL/SQL procedure successfully completed.

SQL> select sql_handle,sql_text,plan_name,creator,last_modified,last_executed,last_verified,accepted from dba_sql_plan_baselines where sql_handle=‘SQL_579305a4a736ac60’;

sql_handle sql_text plan_name creator last_modified last_executed last_verified accepted
SQL_579305a4a736ac60 select count(*) from BASELINE_TEST1 where object_id in (select object_id from BASELINE_TEST2) SQL_PLAN_5g4s5nkmmdb30ed4c7833 sys 20-MAR-2019 20-MAR-2019 (null) YES
SQL_579305a4a736ac60 select count(*) from BASELINE_TEST1 where object_id in (select object_id from BASELINE_TEST2) SQL_PLAN_5g4s5nkmmdb30ed4c7833 sys 20-MAR-2019 20-MAR-2019 (null) YES

使sql plan变为accepted sql plan baseline的几种方法

  1. 调用Dbms_spm.evolve_sql_plan_baseline函数,需要人工调用(在12c版本里已经引入sql plan evolve advisor能实现自动演进sql plan baseline)。
  • Verify=yes 表示经过optimizer验证
  • Verify=no 表示不经过optimizer验证强制变为accepted状态
  1. 调用Dbms_spm.LOAD_PLANS_FROM_CURSOR_CACHE或者LOAD_PLANS_FROM_SQLSET函数,这里使用LOAD_PLANS_FROM_CURSOR_CACHE函数将shared
    pool中已经存在的执行计划load到baseline,且状态变为accepted;
  2. 通过dbms_sqltune对SQL语句进行调优,并接受其调优建议
  • 删除带有索引的baseline
    set serveroutput on
    declare
    result_int pls_integer;
    begin
    result_int:=dbms_spm.drop_sql_plan_baseline(sql_handle=>‘SQL_579305a4a736ac60’,plan_name=>‘SQL_PLAN_5g4s5nkmmdb305e59f0e1’);
    dbms_output.put_line(result_int);
    end;
    /

  • 执行dbms_sqltune,生成并接受优化建议
    生成tuning任务
    declare
    my_task_name varchar2(30);
    my_sqltext clob;
    begin
    my_sqltext:=‘select count(*) from BASELINE_TEST1 where object_id in (select object_id from BASELINE_TEST2)’;
    my_task_name:=dbms_sqltune.create_tuning_task(sql_text=>my_sqltext,user_name=>‘SYS’,scope=>‘COMPREHENSIVE’,time_limit=>60,task_name=>‘sys_sql_tune_1’,description=>‘tune 1’);
    end;
    /
    执行tuning任务
    exec dbms_sqltune.execute_tuning_task(task_name=>‘sys_sql_tune_1’);

查看sqltune报告
set long 9000
set longchunksize 1000
set linesize 800
select dbms_sqltune.report_tuning_task(‘sys_sql_tune_1’) from dual;

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘SYS_SQL_TUNE_1’)

GENERAL INFORMATION SECTION

Tuning Task Name   : sys_sql_tune_1
Tuning Task Owner  : SYS
Workload Type    : Single SQL Statement
Execution Count    : 3
Current Execution  : EXEC_177
Execution Type    : TUNE SQL
Scope     : COMPREHENSIVE
Time Limit(seconds): 60
Completion Status  : COMPLETED

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘SYS_SQL_TUNE_1’)

Started at    : 03/25/2019 09:26:00
Completed at    : 03/25/2019 09:26:01

Schema Name   : SYS
Container Name: CDB$ROOT
SQL ID       : gr4bjs4bhc2v3
SQL Text      : select count(*) from BASELINE_TEST1 where object_id in
  (select object_id from BASELINE_TEST2)

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘SYS_SQL_TUNE_1’)

FINDINGS SECTION (1 finding)

1 SQL Profile Finding (see explain plans section below)

A potentially better execution plan was found for this statement.

Recommendation (estimated benefit: 86.09%)
  
    Consider accepting the recommended SQL profile. The SQL plan baseline
     corresponding to the plan with the SQL profile will also be updated to an

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘SYS_SQL_TUNE_1’)

accepted plan.
     execute dbms_sqltune.accept_sql_profile(task_name => ‘sys_sql_tune_1’,
     task_owner => ‘SYS’, replace => TRUE);

Validation results
  
   The SQL profile was tested by executing both its plan and the original plan
   and measuring their respective execution statistics. A plan may have been
   only partially executed if the other could be run to completion in less time.

Original Plan  With SQL Profile  % Improved

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘SYS_SQL_TUNE_1’)

Completion Status:  COMPLETE   COMPLETE
   Elapsed Time (s):   .01077    .007899      26.65 %
   CPU Time (s):   .010698    .007798 27.1 %
   User I/O Time (s):        0   0
   Buffer Gets:      1536        213      86.13 %
   Physical Read Requests:       0   0
   Physical Write Requests:       0   0
   Physical Read Bytes:        0   0
   Physical Write Bytes:        0   0
   Rows Processed:        1   1

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘SYS_SQL_TUNE_1’)

Fetches:         1   1
   Executions:         1   1

Notes
  
   1. Statistics for the original plan were averaged over 10 executions.
   2. Statistics for the SQL profile plan were averaged over 10 executions.

EXPLAIN PLANS SECTION

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘SYS_SQL_TUNE_1’)

1 Original With Adjusted Cost

Plan hash value: 1308779663

| Id  | Operation       | Name        | Rows  | Bytes | Cost (%CPU)| Time     |

|   0 | SELECT STATEMENT      |         |     1 |    18 |   418  (1)| 00:00:01 |
|   1 |  SORT AGGREGATE       |         |     1 |    18 |     |        |
|*  2 |   HASH JOIN RIGHT SEMI|         |    99 |  1782 |   418  (1)| 00:00:01 |

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘SYS_SQL_TUNE_1’)

|   3 |    VIEW        | VW_NSO_1       |    99 |  1287 |     2  (0)| 00:00:01 |
|   4 |     TABLE ACCESS FULL | BASELINE_TEST2 |    99 |   297 |     2  (0)| 00:00:01 |
|   5 |    TABLE ACCESS FULL  | BASELINE_TEST1 | 91005 |   444K|   416  (1)| 00:00:01 |

Predicate Information (identified by operation id):

2  access(“OBJECT_ID”=“OBJECT_ID”)

2 Using SQL Profile

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘SYS_SQL_TUNE_1’)

Plan hash value: 3701883114

| Id  | Operation        | Name        | Rows  | Bytes | Cost (%CPU)| Time     |

|   0 | SELECT STATEMENT       |        |     1 |    18 |    59 (2)| 00:00:01 |
|   1 |  SORT AGGREGATE        |        |     1 |    18 |     |       |
|*  2 |   HASH JOIN RIGHT SEMI |        |    99 |  1782 |    59 (2)| 00:00:01 |
|   3 |    VIEW         | VW_NSO_1       |    99 |  1287 |     2 (0)| 00:00:01 |
|   4 |     TABLE ACCESS FULL  | BASELINE_TEST2       |    99 |   297 |     2 (0)| 00:00:01 |

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘SYS_SQL_TUNE_1’)

|   5 |    INDEX FAST FULL SCAN| INDEX_BASELINE_TEST1 | 91005 |   444K|    56 (0)| 00:00:01 |

Predicate Information (identified by operation id):

2  access(“OBJECT_ID”=“OBJECT_ID”)

删除sql plan baseline
set serveroutput on
declare
result_int pls_integer;
begin
result_int:=dbms_spm.drop_sql_plan_baseline(sql_handle=>‘SQL_d11d993788ae4828’,plan_name=>‘SQL_PLAN_d27ct6y4awk18b1b38b11’);
dbms_output.put_line(result_int);
end;
/

你可能感兴趣的:(Oracle性能优化(二)SQL Plan Management)