Oracle 11g SQL性能的新特性(三)- SQL Plan Management

SQL Plan Management (SPM)


历史


SQL的执行效率,取决于它的执行计划是否高效。 优化器的算法是一个平衡,需要收集尽量少的信息,用尽量快的速度试图去得到一个最优的执行计划,这也决定了它不是万能的。 所以Oracle提供了一些辅助手段来“修复”优化器可能产生的错误,并不断改进这些方法。 

Oracle 8: hint
Oracle 8i&9: stored outline
Oracle 10: sql profile
Oracle 11: sql plan manangement




简介


在Oracle 11g之前,执行计划一直是作为“运行时”生成的对象存在。虽然oracle提供了一些方法去指导它的生成,但Oracle一直没有试图去保存完整的执行计划。 从11g开始,执行计划就可以作为一类资源被保存下来,允许特定SQL语句只能选择“已知”的执行计划。 


同其他方法相比,SPM更加的灵活。如我们所熟知的,一条带有绑定变量的SQL语句,最好的执行计划会根据绑定变量的值而不同,11g以前的方法都无法解决这个问题。在11g中,与adaptive cursor sharing配合,SPM允许你同时接受多个执行计划。执行时,根据不同的变量值,SPM会花费很少的运算从中选择一条最合适的。 


概念


SQL Plan Management SPM:oracle 11g 中提供的新特性,用来更好地控制执行计划。 
Plan History: 优化器生成的所有执行计划的总称
SQL Plan Baseline: Plan History里那些被标记为“ACCEPTED”的执行计划的总称
Plan Evolution: 把一条执行计划从Plan History里标记为“ACCEPTED”的过程
SQL Management Base SMB: 字典表里保存的执行计划的总称,包括Plan History,SQL Plan Baseline和SQL profile。


SPM的特点


o 与profile和outline相比,更加灵活的控制手段
  + 可以有很多的计划被保存下来,只有"ENABLED"并且"ACCEPTED"的执行计划才可以被选择。 
  + 允许有多个"ACCEPTED"的执行计划,根据实际情况进行选择。 
  + 可以用手工或者自动的方式,把执行计划演化(evolve)为"ACCEPTED"。 还可以控制只让性能更好的计划被接受。
  + 允许设置"FIXED"的计划。这样其他的计划将不会被选择。


o SPM使计划真正的稳定。 outline的缺点是太过死板,当数据量大幅度变化时无法做出相应的改变。 SQL proifle的缺点是,当数据量变化时,STA(SQL Tuning Advisor)会不可预知地去更改执行计划。 而SPM则会提供几个完整的plan供选择。 


SPM的控制方式


SPM通过几个标记来实现对执行计划的控制:


o Enabled (控制活动)
  + YES (活动的,但不一定会被使用)
  + NO (可以理解为被标记删除)
o Accepted (控制使用)
  + YES (只有 “Enabled” 并且 “Accepted” 的计划才会被选择使用)
  + NO (如果是“Enabled” 那么只有被evolve成“Accepted”才有可能被执行)
o Fixed (控制优先级)
  + YES (如果是“Enabled”并且“Accepted”,会优先选择这个计划,这个计划会被视为不需要改变的)
  + NO (普通的计划,无需优先)

另有一个被动的标记:
o Reproduced (有效性)
  + YES (优化器可以使用这个计划)
  + NO (计划无效,比如索引被删除)


SPM如何捕捉执行计划


o 自动捕捉
  1. 首先把OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES设置成TRUE
  2. 从这个时刻开始,所有执行两次以上的SQL语句会被观测,执行计划会进入Plan History。有个别例外的,参见note 788853.1
  3. 生成的第一个执行计划被标记为ENABLED并且是ACCEPTED,后续的执行计划会被标记为ENABLED但不是ACCEPTED。
  4. 这时把OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES设置会FALSE,新的语句将不会创建Baseline。
  5. 需要注意的是,即使关闭了自动捕捉,针对存在baseline的SQL,由于ACS的作用,仍旧会有新的PLAN生成,新的Plan仍会进入Plan History,标记为ENABLED但不是ACCEPTED。参见“执行计划的选择”。 


o 批量导入 (这些导入的baseline都会被自动标记为ACCEPTED) 
   Oralce提供四种方式把计划导入到sql plan baseline中。 
   + 从 SQL Tuning Set STS 导入
      DBMS_SPM.LOAD_PLANS_FROM_SQLSET
   + 从Stored Outlines 中导入 
      DBMS_SPM.MIGRATE_STORED_OUTLINE
   + 从内存中存在的计划中导入
      DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE;
   + 通过staging table从另外一个系统中移植
      DBMS_SPM.CREATE_STGTAB_BASELINE
      DBMS_SPM.PACK_STGTAB_BASELINE
      DBMS_SPM.UNPACK_STGTAB_BASELINE




执行计划的选择过程


在OPTIMIZER_USE_SQL_PLAN_BASELINES被设置成默认值TRUE,SQl Plan Baseline就会起作用。 


1. 首先,无论是否存在baseline,oracle都会正常进行硬解析或者软解析,为SQL生成一个执行计划。 由于ACS和bind peeking的作用,存在baseline的SQL有可能在这时生成一个不同于baseline的执行计划。
2. 如果baseline不存在,就按生成的计划执行。如果baseline存在,那么要查看history里是否有这个计划,如果没有,就将这个计划插入,并标记为ENABLED,NON-ACCEPTED. 
3. 在baseline中查看是否有FIXED的计划存在,如果存在,执行FIXED的计划,如果存在多个FIXED的计划,根据统计信息重新计算cost,选择cost小的那个。
4. 如果FIXED的计划不存在,就选择ACCEPTED的计划执行。 如果存在多个ACCEPTED的计划,根据统计信息重新计算cost,选择cost小的那个。


* 注意这里每次重新计算cost的代价不大,因为执行计划是已知的,优化器不必遍历所有的可能,只需根据算法计算出已知计划的cost便可


执行计划的演化(evolution)


执行计划的演化指Plan History里的执行计划从NON-ACCEPTED,变成ACCEPTED的过程。 如果上所述,由于ACS和Bind Peeking的作用,存在baseline的SQL有可能生成新的执行计划,被保存到Plan History中。 Oracle提供了API,通过自动或手工的方式,将一个计划标记为ACCEPTED,这个计划就会被后续的执行所选择。 


使用DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE这个API来控制执行计划的演化。语法:
DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE (
  sql_handle IN VARCHAR2 := NULL, --> NULL 表示针对所有SQL
  plan_name  IN VARCHAR2 := NULL,
  time_limit IN INTEGER  := DBMS_SPM.AUTO_LIMIT,
  verify     IN VARCHAR2 := ‘YES‘,
  commit     IN VARCHAR2 := ‘YES‘ )
RETURN CLOB;


这里由两个标记控制:
o Verify 
  + YES (只有性能更好的计划才会被演化)
  + NO (演化所有的计划)
o Commit
  + YES (直接演化)
  + NO (只生成报告)


这里可以通过不同的排列组合,达到不同的效果:
o 自动接收所有性能更好的执行计划 (Verify->YES, Commit->YES)
o 自动接收所有新的执行计划 (Verify->NO, Commit->YES)
o 比较性能,生成报告,人工确认是否演化 (Verify->NO, Commit->NO)


* 对于性能的验证的方式,oracle会去实际执行来比较buffer gets


修改已有的Baseline


通过DBMS_SPM.ALTER_SQL_PLAN_BASELINE来完成。 


DBMS_SPM.ALTER_SQL_PLAN_BASELINE (
  sql_handle      IN VARCHAR2 := NULL,
  plan_name       IN VARCHAR2 := NULL,
  attribute_name  IN VARCHAR2,
  attribute_value IN VARCHAR2 )
RETURN PLS_INTEGER;


比如,把某个baseline 标记为FIXED,更多属性请参见官方文档


SET SERVEROUT ON;
DECLARE
  x NUMBER;
BEGIN
  x := DBMS_SPM.ALTER_SQL_PLAN_BASELINE (
    sql_handle      => ‘&&sql_handle‘,
    plan_name       => ‘&&plan_name‘,
    attribute_name  => ‘FIXED‘,
    attribute_value => ‘YES‘ );
END;
/


常见应用


o 我们常见的一个场景是,一条SQL在使用hint时会生成一个好的计划,我们需要以此在原SQL上创建一个baseline。 具体方法请参加note 787692.1


注意


o 当您使用多种方式控制执行计划时:
  + Stored Outline存在时,它具有最高的优先级。
  + 已经实施的SQL profile会被自动加入到SQL plan baseline中
  + STA(SQL Tuning Advisor) 会自动接收新的profile,意味着它会生成新的baseline
o 如果可能话,尽量移植到SPM,混合多种方式会变得复杂


相关参数


optimizer_capture_sql_plan_baselines
optimizer_use_sql_plan_baselines
create_stored_outline
use_stored_outlines

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。