(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计划基线功能, 从而提高性能。