(1)启用执行计划基线
SQL> alter system set optimizer_capture_sql_plan_baselines=true;
System altered.
--declare
-- rs pls_integer;
-- begin
-- rs:=dbms_spm.load_plans_from_cursor_cache('4s1dw29xzc2rs');
-- end;
-- /
--PL/SQL procedure successfully completed.
(2)执行旧SQL和新SQL,让执行计划加载到计划基线中。
select id from test01 where id>800000; select /*+full(test01)*/id from test01 where id>800000; --找执行过的SQL对应的SQL_ID; SQL> col SQL_TEXT for a100 SQL> set lin 200 SQL> select SQL_TEXT,SQL_ID from v$sqlarea where SQL_TEXT like '%test01%' and upper(SQL_TEXT) not like 'EXPLAIN%' and SQL_TEXT like '%where id>800000'; SQL_TEXT SQL_ID ---------------------------------------------------------------------------------------------------- ------------- select id from test01 where id>800000 a05acgcuwzfwm select /*+full(test01)*/id from test01 where id>800000 0wg3z9uhv7umc SQL> col SQL_TEXT for a50 SQL> col CREATED for a40 SQL> set lin 200 SQL> select sql_handle, plan_name,enabled accepted, fixed,created,SQL_TEXT from dba_sql_plan_baselines; SQL_HANDLE PLAN_NAME ACC FIX CREATED SQL_TEXT ------------------------------ ------------------------------ --- --- ---------------------------------------- -------------------------------------------------- SQL> select sql_handle, plan_name,enabled, accepted, fixed,created,SQL_TEXT from dba_sql_plan_baselines; SQL_HANDLE PLAN_NAME ENA ACC FIX CREATED SQL_TEXT ----------------------------------------------------- --- --- ---------------------------------------- -------------------------------------------------- SQL_2112181b20c8066e SQL_PLAN_224hs3chch1mff98b55bb YES YES NO 23-JAN-24 06.10.57.000000 PM select id from test01 where id>800000 SQL_344ebb56d048d47e SQL_PLAN_38mpvav84jp3y04c70b35 YES YES NO 23-JAN-24 05.58.47.000000 PM select /*+full(test01)*/id from test01 where id>800000 SQL_c12964b9d3f12200 SQL_PLAN_c2ab4r79z28h0f98b55bb YES YES NO 23-JAN-24 05.56.04.000000 PM select id from test01 where id>800000
(3)如果要删除固定的执行计划。
--我们暂时不做删除。 --declare --xx PLS_INTEGER; --BEGIN --xx :=dbms_spm.drop_sql_plan_baseline(sql_handle=>'SQL_344ebb56d048d47e',plan_name=>'SQL_PLAN_38mpvav84jp3y04c70b35'); --END; --/
(4)停用原基线
--select id from test01 where id>800000 --停用旧SQL的执行计划; declare rs pls_integer; begin rs:=DBMS_SPM.ALTER_SQL_PLAN_BASELINE ( plan_name=>'SQL_PLAN_c2ab4r79z28h0f98b55bb', attribute_name=>'ENABLED', attribute_value=>'NO'); end; / PL/SQL procedure successfully completed. --这里虽然停用了,ACCEPT=YES,没有变。 --ENABLED=NO; 停用了。 --可以看到,ENABLED=NO,停用了。 select sql_handle, plan_name,enabled,accepted, fixed,created,SQL_TEXT from dba_sql_plan_baselines; SQL_HANDLE PLAN_NAME ENA ACC FIX CREATED SQL_TEXT --------------------------------------------------- --- --- --- ---------------------------------------- -------------------------------------------------- SQL_c12964b9d3f12200 SQL_PLAN_c2ab4r79z28h004c70b35 YES YES YES 23-JAN-24 06.23.47.000000 PM select id from test01 where id>800000 SQL_c12964b9d3f12200 SQL_PLAN_c2ab4r79z28h0f98b55bb NO YES NO 23-JAN-24 05.56.04.000000 PM select id from test01 where id>800000
--(5)变更前执行计划。
SQL> select * from table(dbms_xplan.display_cursor('a05acgcuwzfwm',null,null));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID a05acgcuwzfwm, child number 0
-------------------------------------
select id from test01 where id>800000
Plan hash value: 578627003
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 490 (100)| |
|* 1 | INDEX RANGE SCAN| IDX_ID | 191K| 2432K| 490 (1)| 00:00:06 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("ID">800000)
Note
-----
- dynamic sampling used for this statement (level=2)
22 rows selected.
(6)变更执行计划
--变更执行计划。
--连接新基线
declare
ln_ps pls_integer;
begin
ln_ps:=dbms_spm.load_plans_from_cursor_cache
(sql_id=>'0wg3z9uhv7umc', --新SQL的sql_id
plan_hash_value=>262542483, --新SQL的plan_hash_value
sql_handle=>'SQL_c12964b9d3f12200' --旧sql_handle
);
end;
/
--查看执行计划,执行计划已经变更。
SQL> select * from table(dbms_xplan.display_cursor('a05acgcuwzfwm',null,null));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID a05acgcuwzfwm, child number 0
-------------------------------------
select id from test01 where id>800000
Plan hash value: 578627003
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 490 (100)| |
|* 1 | INDEX RANGE SCAN| IDX_ID | 191K| 2432K| 490 (1)| 00:00:06 |
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("ID">800000)
Note
-----
- dynamic sampling used for this statement (level=2)
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID a05acgcuwzfwm, child number 2
-------------------------------------
select id from test01 where id>800000
Plan hash value: 262542483
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
|* 1 | TABLE ACCESS FULL| TEST01 | 4 | 52 | 2 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID">800000)
Note
-----
- SQL plan baseline SQL_PLAN_c2ab4r79z28h004c70b35 used for this statement
44 rows selected.
--虽然有两个执行计划,但是这里显然使用了新的执行计划:SQL_PLAN_c2ab4r79z28h004c70b35。
(7)ACCEPTED字段说明
--一个SQL语句对应的基线,我将它们归纳为三种状态 1.accepted(可接受),只有这种状态的基线,优化器才会考虑此基线中的执行计划 2.no-accepted(不可接受),这种状态的基线,优化器在SQL语句解析期间不会考虑。这种状态的基线必须通过演化和验证通过后,转变为accepted状态后,才会被优化器考虑使用 3.fixed为yes(固定),这种状态的基线固有最高优先级!比其他两类基线都要优先考
(8)固定执行计划
--1)固定前检查。
col SQL_TEXT for a50
col CREATED for a40
set lin 200
select sql_handle, plan_name, accepted, fixed,created,SQL_TEXT from dba_sql_plan_baselines;
SQL_HANDLE PLAN_NAME ACC FIX CREATED SQL_TEXT
----------------------- ------------------------------ --- --- ---------------------------------------- --------------------------------------------------
SQL_344ebb56d048d47e SQL_PLAN_38mpvav84jp3y04c70b35 YES NO 23-JAN-24 05.58.47.000000 PM select /*+full(test01)*/id from test01 where id>800000
SQL_c12964b9d3f12200 SQL_PLAN_c2ab4r79z28h004c70b35 YES NO 23-JAN-24 06.23.47.000000 PM select id from test01 where id>800000
SQL_c12964b9d3f12200 SQL_PLAN_c2ab4r79z28h0f98b55bb YES NO 23-JAN-24 05.56.04.000000 PM select id from test01 where id>800000
--2)查看执行计划,执行计划已经变更。
--由原来的索引范围扫描变更为,全表扫描。
select id from test01 where id>800000;
select * from table(dbms_xplan.display_cursor());
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID a05acgcuwzfwm, child number 2
-------------------------------------
select id from test01 where id>800000
Plan hash value: 262542483
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
|* 1 | TABLE ACCESS FULL| TEST01 | 4 | 52 | 2 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID">800000)
Note
-----
- SQL plan baseline SQL_PLAN_c2ab4r79z28h004c70b35 used for this statement
22 rows selected.
--SQL_c12964b9d3f12200 SQL_PLAN_c2ab4r79z28h004c70b35
--3)固定这个执行计划。
DECLARE
i NATURAL;
BEGIN
i := dbms_spm.alter_sql_plan_baseline(
'SQL_c12964b9d3f12200',
'SQL_PLAN_c2ab4r79z28h004c70b35',
attribute_name => 'FIXED',
attribute_value => 'YES');
dbms_output.put_line(i);
END;
/
--(9)固定完执行计划检查
col SQL_TEXT for a50 col CREATED for a40 set lin 200 select sql_handle, plan_name, accepted, fixed,created,SQL_TEXT from dba_sql_plan_baselines; SQL_HANDLE PLAN_NAME ACC FIX CREATED SQL_TEXT ----------------------- ------------------------------ --- --- ---------------------------------------- -------------------------------------------------- SQL_c12964b9d3f12200 SQL_PLAN_c2ab4r79z28h004c70b35 YES YES 23-JAN-24 06.23.47.000000 PM select id from test01 where id>800000 SQL_c12964b9d3f12200 SQL_PLAN_c2ab4r79z28h0f98b55bb YES NO 23-JAN-24 05.56.04.000000 PM select id from test01 where id>800000 --可以看到:SQL_PLAN_c2ab4r79z28h004c70b35,已经固定到SQL上。
(10)再次查看执行计划
select id from test01 where id>800000;
select * from table(dbms_xplan.display_cursor());
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID a05acgcuwzfwm, child number 2
-------------------------------------
select id from test01 where id>800000
Plan hash value: 262542483
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
|* 1 | TABLE ACCESS FULL| TEST01 | 4 | 52 | 2 (0)| 00:00:01 |
PLAN_TABLE_OUTPUT
----------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID">800000)
Note
-----
- SQL plan baseline SQL_PLAN_c2ab4r79z28h004c70b35 used for this statement
22 rows selected.
我们的执行计划绑定成功。
(11)总结
执行计划绑定使用SQL_PROFILE绑定时,总是绑定失败,还是使用原来的执行计划。 SPM可以绑定执行计划: 1)optimizer_capture_sql_plan_baselines=true; 2)执行替换前SQL,替换后SQL,此时会缓存到计划基线中; 3)停用SQL的旧的执行计划,绑定新的执行计划到旧SQL; 4)验证SQL的执行计划已经变更。 5)optimizer_capture_sql_plan_baselines参数的取值有以下有三种: 1、FALSE:此参数将关闭sql计划基线功能,不捕获计划基线; 2、TRUE:此参数将启用sql计划基线功能,捕获计划基线; 3、FORCE:此参数将强制oracle数据库总是将当前执行的sql语句的计划捕获为基线, 而不管sql语句是否已经捕获过计划基线。 6)正确设置optmizer_capture_sql_plan_baselines的参数,需要考虑以上三种取值中的特性, 并根据oracle数据库的实际性能需求进行选择: --TRUE; 如果oracle数据库的服务质量要求较高,但数据库的性能不允许增加消耗, 我们可以将优化器参数optimizer_capture_sql_plan_baselines设置为TRUE, 以利用oracle数据库自动优化sql计划基线的功能。 --FORCE; 如果对于数据库性能有一定要求,可以将优化器参数optimizer_capture_sql_plan_baselines设置为FORCE, 使oracle数据库系统总是将当前执行的sql语句的计划捕获为基线,以确保语句持续获得最佳性能。 --FALSE; 如果不需要oracle数据库自动优化sql计划基线的功能,我们可以将优化器参数 optimizer_capture_sql_plan_baselines设置为FALSE,此时oracle数据库系统会忽略sql计划基线功能, 从而提高性能。