目录html
当optimizer_capture_sql_plan_baselines参数设置为TRUE,查询优化器自动存储新SQL计划的基线,默认是FALSE。sql
第一个SQL语句被执行只是把signature插入到log日志中,第二次相同的语句执行时,一个SQL执行基线仅包含建立当前执行计划并标记被接受。第三次执行相同的语句时,基线的中执行计划和当前的执行计划作比较,若是不匹配,根据当前的查询优化器作评估,为了保存这些信息,会把当前的执行计划写入sql基线中并标记不接受。ide
当先的执行计划被存储到SQL执行基线中,如下两种状况很重要作区分优化
为了手工加载SQL执行基线加载到数据字典中基于在libarary cache中游标存储,这个dbms_spm包中的load_plans_from_cursor_cache是可用的。ui
能够把执行计划中原本是全表扫描的,不更改任何的SQL语句,使它走索引的模式。spa
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;
查看执行计划code
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_handleorm
SELECT sql_handle FROM dba_sql_plan_baselines WHERE plan_name ='SQL_PLAN_6bu51x6d0cb5215f09a65';
再使语句走INDEX的模式,手工构造HINTS模式htm
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字段
ret := dbms_spm.load_plans_from_sqlset(sqlset_name => 'test_sqlset', sqlset_owner => user);