在ORACLE数据库中SQL效率的突然衰减通常是因为目标SQL的执行计划发生改变。(应用升级导致SQL执行次数变化非常大也有可能导致,但是不是单个SQL的问题了)
此时,通常通过重新收集统计信息或修改SQL(加HINT)来解决。但是有时收集统计信息并不能解决,而且无法修改SQL,此时就需要用到其它方法来固定执行计划。
常用的固定执行计划的方法有以下:
9I:stored outline
10G:SQL PROFILE(automatic/manual)
11G:SPM /SQL PROFILE(automatic/manual)
1.使用SQL PROFILE来稳定执行计划
是9I:stored outline的进化,9I:stored outline能实现的功能SQL PROFILE也完全能实现。
SQL PROFILE的优点:
更容易生成,更改和控制
对SQL语句的支持上做得更好,适应范围更广
很容易实现锁定或稳定执行计划、在不能修改目标SQL的SQL文本情况下使目标SQL语句按指定执行计划运行。
#############
SQLT工具中的COE系列脚本-sqlt\utl目录:
1.coe_xfr_sql_profile.sql脚本
适用于当前数据库中同一SQL有多个执行计划(内存或AWR数据中)时进行绑定;
通过替换hint数据也可以实现将另一个SQL(一般是加HINT)的较好执行计划,绑定到目标SQL上。
2.coe_load_sql_profile.sql
同一数据库中两个SQL(一般有一个是加了HINT)的执行计划,用加hint的更优执行计划,替换目标SQL当前的执行计划。
跨数据库也可以进行这种替换执行计划。
3.coe_load_sql_baseline.sql
同一数据库中两个SQL(一般有一个是加了HINT)的执行计划,用加hint的更优执行计划,替换目标SQL当前的执行计划。
跨数据库也可以进行这种替换执行计划。
脚本执行步骤:
1.获取原始SQL文本、修改SQL的PHV
2.为modified_sql手动创建基线
3.通过DBMS_SPM.ALTER_SQL_PLAN_BASELINE attribute_value修改基线对应成原始SQL
4.CREATE_STGTAB_BASELINE创建表并导出BASELINE数据
参考MOS文档:
Automatic SQL Tuning and SQL Profiles (文档 ID 271196.1)
Whitepaper: SQL Plan Management in Oracle Database 11g
Master Note: Plan Stability Features (Including SQL Plan Management (SPM)) (文档 ID 1359841.1)
FAQ: SQL Plan Management (SPM) Frequently Asked Questions (文档 ID 1524658.1)
How to Use SQL Plan Management (SPM) – Plan Stability Worked Example (文档 ID 456518.1)
How to Accept & Unaccept Plans in SQL Plan Baselines (文档 ID 1309799.1)
How to Drop Plans from the SQL Plan Management (SPM) Repository (文档 ID 790039.1)
Loading Hinted Execution Plans into SQL Plan Baseline. (文档 ID 787692.1)
–>Document 215187.1 SQLTXPLAIN offers a script ( ./utl/coe_load_sql_baseline.sql ) to automate the steps
Transporting SQL PLAN Baselines from One Database to Another. (文档 ID 880485.1)
迁移SQL PLAN Baselines
How to Load SQL Plans into SQL Plan Management (SPM) from the Automatic Workload Repository (AWR) (文档 ID 789888.1)
How to Move a SQL Tuning Set from One Database to Another (文档 ID 751068.1)
Automatic SQL Tuning and SQL Profiles (文档 ID 271196.1)
How to Move SQL Profiles from One Database to Another (Including to Higher Versions) (文档 ID 457531.1)
1.通过COE系列脚本:coe_xfr_sql_profile.sql脚本固定执行计划的测试:
—注意脚本中force_match=>FALSE要修改为force_match=>TRUE
–删除SQLPROFILE:
SQL>exec dbms_sqltune.drop_sql_profile(name => ‘coe_2r2qpwfmc2fwp_190799060′);
PL/SQL procedure successfully completed.
情况1:当前内存或AWR中已经有同一SQL的不同执行计划,且不同的执行计划中有正确 的执行计划,此时使用方法如下:
1.通过SQL_TEXT查出SQL_ID,执行如下命令生成脚本,再执行脚本来固定执行计划:
SQL> @coe_xfr_sql_profile.sql
Parameter 1:
SQL_ID (required)
Enter value for 1: d3124k0m9ppwf
PLAN_HASH_VALUE AVG_ET_SECS
————— ———–
4127820982 .035
Parameter 2: —输入通过SQL_ID得到的不同HASH_VALUE中的正确值:4127820982
Execute coe_xfr_sql_profile_d3124k0m9ppwf_4127820982.sql
on TARGET system in order to create a custom SQL Profile
with plan 4127820982 linked to adjusted sql_text.
COE_XFR_SQL_PROFILE completed.
在SQLPLUS窗口中执行此coe_xfr_sql_profile_d3124k0m9ppwf_4127820982.sql文件然后验证即可。
验证SQL执行情况:
select EXECUTIONS,PLAN_HASH_VALUE,ELAPSED_TIME/1000000,ELAPSED_TIME/1000000/EXECUTIONS,LAST_ACTIVE_TIME,ROWS_PROCESSED
from v$sql where EXECUTIONS>0 and sql_id=’g87an0j5djjpm’ order by last_active_time desc;
2.通过SPM固定执行计划的方法
ORACLE在11G推出了SPM sql plan management,是一种主动的稳定执行计划的手段,能够保证只有被验证过的执行计划才会被启用。
在目标SQL产生新执行计划后,新执行计划不会被启用,需要由用户确认是否启用。
SPM首先可以主动稳定执行计划,同时对于可能出现的更高效的执行计划,也可能得到使用。
启用SPM后,每个SQL对应一个SQL PLAN baseline–Oracle SQL执行计划基线,存储对应的执行计划.当SQL有多个执行计划,该SQL可能有多个SQL PLAN baseline–dba_sql_plan_baselines.
dba_sql_plan_baselines中的列ENABLED/ACCEPTED用来描述一个SQL PLAN baseline所对应的执行计划是否被启用。
只有列ENABLED/ACCEPTED值均为YES才会被启用。当一条SQL有超过1列ENABLED/ACCEPTED均为YES的执行计划,ORACLE会选择COST小的执行计划。
在ORACLE 11G及以上版本,有如下 两种方法可以生成目标SQL的SQL PLAN baseline.
1.自动捕获,手工切换使用
2.手工生成/批量导入(适合大版本升级,确保升级后执行计划不变更)
########################################
命令汇总:
show parameter use_sql_plan
alter session set optimizer_capture_sql_plan_baselines=TRUE;
alter session set optimizer_use_sql_plan_baselines=FALSE;
set linesize 300
set pagesize 1000
select SQL_HANDLE,SQL_TEXT,PLAN_NAME,ORIGIN,ENABLED,ACCEPTED from dba_sql_plan_baselines
where sql_text like ‘select object_id,object_name from t8 where object_id between 300 and 400%’;
###将dba_sql_plan_baselines的列ACCEPTED设置为YES。(只能从NO改为YES,不能从YES改为NO)
var temp varchar2(1000);
exec :temp := dbms_spm.evolve_sql_plan_baseline(sql_handle=>’SQL_4fa41df4e6247591′,plan_name=>’SQL_PLAN_4z90xymm28xcjec50a0c0′,verify=>’NO’,commit=>’YES’);
###将dba_sql_plan_baselines的列ENABLED设置为YES。–需要指定sql_handle,plan_name
var temp varchar2(1000);
exec :temp := dbms_spm.alter_sql_plan_baseline(sql_handle=>’SQL_4fa41df4e6247591′,plan_name=>’SQL_PLAN_4z90xymm28xcj9576b900′,attribute_name=>’ENABLED’,attribute_value=>’YES’);
###将dba_sql_plan_baselines的列ENABLED设置为NO,禁用了此执行计划。–需要指定sql_handle,plan_name
var temp varchar2(1000);
exec :temp := dbms_spm.alter_sql_plan_baseline(sql_handle=>’SQL_4fa41df4e6247591′,plan_name=>’SQL_PLAN_4z90xymm28xcjec50a0c0′,attribute_name=>’ENABLED’,attribute_value=>’NO’);
exec DBMS_STATS.GATHER_TABLE_STATS ( ownname=>’BYS’,tabname =>’T8′,estimate_percent=>100,cascade=>TRUE);
exec DBMS_STATS.SET_INDEX_STATS( ownname=>’BYS’,indname =>’IDX_T8′,clstfct=>10000000,no_invalidate=>false);
验证SQL执行情况:
select EXECUTIONS,PLAN_HASH_VALUE,ELAPSED_TIME/1000000,ELAPSED_TIME/1000000/EXECUTIONS,LAST_ACTIVE_TIME,ROWS_PROCESSED
from v$sql where EXECUTIONS>0 and sql_id=’g87an0j5djjpm’ order by last_active_time desc;