spm 捕获

目录

  1. 自动捕获
  2. 从library cache 中加载
  3. 从SQL 调优级加载

1、自动捕获

当optimizer_capture_sql_plan_baselines参数设置为TRUE,查询优化器自动存储新SQL计划的基线,默认是FALSE。

第一个SQL语句被执行只是把signature插入到log日志中,第二次相同的语句执行时,一个SQL执行基线仅包含创建当前执行计划并标记被接受。第三次执行相同的语句时,基线的中执行计划和当前的执行计划做比较,如果不匹配,根据当前的查询优化器做评估,为了保存这些信息,会把当前的执行计划写入sql基线中并标记不接受。

当先的执行计划被存储到SQL执行基线中,以下两种情况很重要做区分

  • 如果他是SQL执行基线中第一个执行计划,执行计划被存储并接受,随后,查询优化器会重用它。
  • 如果SQL语句执行基线中不是第一个执行计划,他会存储不被接受,最后结果,查询优化器不被使用。

 

2、从library cache 中加载

为了手工加载SQL执行基线加载到数据字典中基于在libarary cache中游标存储,这个dbms_spm包中的load_plans_from_cursor_cache是可用的。

可以把执行计划中本来是全表扫描的,不更改任何的SQL语句,使它走索引的模式。

ALTER SESSION SET optimizer_capture_sql_plan_baselines = TRUE;
SELECT /*+ full(t) */ * FROM employees  where employee_id>110;

ALTER SESSION SET optimizer_capture_sql_plan_baselines = FALSE;
 

重新运行语句

SELECT /*+ full(t) */ * FROM employees  where employee_id>110;

查看执行计划

select * from table(dbms_xplan.display_cursor(null,null));
SQL_ID  b2j5kmkx67r6t, child number 3
-------------------------------------
SELECT /*+ full(t) */ * FROM employees  where employee_id>110
 
Plan hash value: 603312277
 
---------------------------------------------------------------------------------------------
| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |               |       |       |     4 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |    97 |  6693 |     4   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | EMP_EMP_ID_PK |    97 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("EMPLOYEE_ID">110)
 
Note
-----
   - SQL plan baseline
SQL_PLAN_6bu51x6d0cb5215f09a65

通过执行计划中NOTE信息获取sql_handle

 SELECT sql_handle
FROM dba_sql_plan_baselines
WHERE plan_name ='SQL_PLAN_6bu51x6d0cb5215f09a65';

再使语句走INDEX的模式,手工构造HINTS模式

 select /*+index(employees emp_emp_id_pk)*/ * from  employees where employee_id>110;
 
 select * from table(dbms_xplan.display_cursor(null,null));
SQL_ID  0gd91j77ppkc7, child number 0
-------------------------------------
select /*+index(employees emp_emp_id_pk)*/ * from  employees where 
employee_id>110
 
Plan hash value: 603312277
 
---------------------------------------------------------------------------------------------
| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |               |       |       |     4 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |    97 |  6693 |     4   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | EMP_EMP_ID_PK |    97 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("EMPLOYEE_ID">110)
 

替换使用在sql基线中的执行计划,加载的执行计划关联索引的,移除全部扫描

declare
ret number(20);
begin
ret := dbms_spm.load_plans_from_cursor_cache(sql_handle => 'SQL_65e8a1e99a062ca2',
sql_id => '0gd91j77ppkc7',
plan_hash_value => '603312277');
end;

declare
ret number(20);
begin
ret :=dbms_spm.drop_sql_plan_baseline(sql_handle => 'SQL_65e8a1e99a062ca2',
plan_name => 'SQL_PLAN_6bu51x6d0cb52cf314e9e');
end;

再次执行SQL语句

SELECT /*+ full(t) */ * FROM employees  where employee_id>110; 

select * from table(dbms_xplan.display_cursor(null,null));

SQL_ID  b2j5kmkx67r6t, child number 3
-------------------------------------
SELECT /*+ full(t) */ * FROM employees  where employee_id>110
 
Plan hash value: 603312277
 
---------------------------------------------------------------------------------------------
| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |               |       |       |     4 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |    97 |  6693 |     4   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | EMP_EMP_ID_PK |    97 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("EMPLOYEE_ID">110)
 
Note
-----
   - SQL plan baseline 
SQL_PLAN_6bu51x6d0cb5215f09a65 

全表扫描的SQL语句已经替换为index的模式来处理,为了确认是否使用了SQL基线,你可以核对V$SQL中的SQL_PLAN_BASELINE字段

3、从SQL TUNING SET加载

ret := dbms_spm.load_plans_from_sqlset(sqlset_name => 'test_sqlset',
sqlset_owner => user);
posted @ 2018-03-29 10:12  gull  Views(198)  Comments(0Edit  收藏  举报