11g新特性SQL执行计划管理(SQL Plan Management) (1)
数据库系统性能受到查询执行的严重影响。然而SQL语句的执行计划可能因统计信息变化,优化参数变化或方案定义变化等原因而意外改变,Oracle Optimizer优化器往往无法在没有人工干预的情况下准确进化执行计划。在无法保证新的执行计划总是趋于变得更好的情况下,用户倾向于通过存储大纲(stored outline)或锁定统计信息来保证执行计划的问题。然而使用这些方式将不可避免地丧失利用到新的优化器特性以改善SQL语句性能的优势。在保证当前可被接受执行计划的前提下,仅允许采用那些更好的,获益更多的执行计划才是终极方案。
Oracle Database 11g是在解决这一SQL执行计划上处于市场领先地位。SQL Plan Management(SPM)提供了一个完全透明且可控的执行计划进化的框架。在SPM的帮助下优化器自动管理执行计划并保证只有已知或已确认的执行计划才被采用。当一个新的计划出现时,Oracle将不会采用它,直到确认其与当前的执行计划有着相当的,或更好的性能。
SQL Plan Management(SPM)保证数据库运行时性能绝不因为执行计划的改变而大幅下降。为了确保这一点,仅仅那些已被接受的(accepted or trusted)的执行计划将被采用;任何计划的进化都将被追踪并仅在其被评价为无损于性能或有益于性能后被采纳。
SPM主要由三个部分组成:
1.执行计划基线捕捉
创建SQL执行计划基线意味着接受(或者说信任)相关SQL语句的执行计划。SQL计划基线存储在历史计划中,历史计划保存在SQL Management BASE(SMB)中,SMB位于SYSAUX表空间上。
SQL> select * from v$version; BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production PL/SQL Release 11.2.0.2.0 - Production CORE 11.2.0.2.0 Production TNS for Linux: Version 11.2.0.2.0 - Production NLSRTL Version 11.2.0.2.0 - Production SQL> select occupant_name,space_usage_kbytes from v$sysaux_occupants where occupant_name like '%SQL%'; OCCUPANT_NAME SPACE_USAGE_KBYTES ---------------------------------------------------------------- ------------------ SQL_MANAGEMENT_BASE 37762.SQL计划基线选择 保证仅采用SQL计划基线中已被信任的执行计划,并追踪计划历史中所有新的执行计划。计划历史中包括了受信任的和不受信任的执行计划。不受信任的执行计划可能是未被检验的(unverified)或被拒绝的(rejected)。 3.SQL计划基线进化 在历史计划中为给定SQL语句评估所有未被检验的执行计划,这些执行计划有的被评估为可接受的(可信任的),有的则被驳回(rejected)。 图示0 SQL Management Base,由语句记录和历史计划等组成。
SQL> set autotrace traceonly exp; SQL> select * from DBA_SQLSET; Execution Plan ---------------------------------------------------------- Plan hash value: 3125220660 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | 168 | 3 (0)| 00:00:01 | | 1 | TABLE ACCESS FULL| WRI$_SQLSET_DEFINITIONS | 2 | 168 | 3 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- /* sqlset信息来源于基表WRI$基表,即Workload Repository Internal */ SQL> select * from dba_sql_plan_baselines; Execution Plan ---------------------------------------------------------- Plan hash value: 3413624941 -------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 2723 | 1 (0)| 00:00:01 | | 1 | FIXED TABLE FULL | X$MODACT_LENGTH | 1 | 13 | 0 (0)| 00:00:01 | | 2 | FIXED TABLE FULL | X$MODACT_LENGTH | 1 | 13 | 0 (0)| 00:00:01 | | 3 | NESTED LOOPS | | | | | | | 4 | NESTED LOOPS | | 1 | 2723 | 1 (0)| 00:00:01 | | 5 | NESTED LOOPS | | 1 | 691 | 1 (0)| 00:00:01 | |* 6 | INDEX SKIP SCAN | SQLOBJ$_PKEY | 1 | 82 | 1 (0)| 00:00:01 | | 7 | TABLE ACCESS BY INDEX ROWID| SQLOBJ$AUXDATA | 1 | 609 | 0 (0)| 00:00:01 | |* 8 | INDEX RANGE SCAN | I_SQLOBJ$AUXDATA_PKEY | 1 | | 0 (0)| 00:00:01 | |* 9 | INDEX UNIQUE SCAN | I_SQL$TEXT_PKEY | 1 | | 0 (0)| 00:00:01 | | 10 | TABLE ACCESS BY INDEX ROWID | SQL$TEXT | 1 | 2032 | 0 (0)| 00:00:01 | -------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 6 - access("SO"."OBJ_TYPE"=2) filter("SO"."OBJ_TYPE"=2) 8 - access("SO"."SIGNATURE"="AD"."SIGNATURE" AND "AD"."OBJ_TYPE"=2 AND "SO"."PLAN_ID"="AD"."PLAN_ID") filter("AD"."OBJ_TYPE"=2 AND "SO"."PLAN_ID"="AD"."PLAN_ID") 9 - access("AD"."SIGNATURE"="ST"."SIGNATURE") filter("SO"."SIGNATURE"="ST"."SIGNATURE") Note ----- - dynamic sampling used for this statement (level=3) - SQL plan baseline "SQL_PLAN_9s3btm2sx51n074830d3a" used for this statement /* 这里启用了一个基线中的计划 */ /* 可以看到SQL计划基线的数据SQL$TEXT等基表中,不同于WRI */ SQL> desc sql$; Name Null? Type ----------------------------------------- -------- ---------------------------- SIGNATURE NOT NULL NUMBER INUSE_FEATURES NOT NULL NUMBER FLAGS NOT NULL NUMBER SPARE1 NUMBER SPARE2 CLOB SQL> desc sqllog$; Name Null? Type ----------------------------------------- -------- ---------------------------- SIGNATURE NOT NULL NUMBER BATCH# NOT NULL NUMBER
SQL计划基线捕获
为了支持SPM和新建立的执行计划的性能验证,我们必须首次以基于成本的执行计划填充SQL Management Base,这些执行计划将成为首批的计划基线。我们有2种方式来填充SQL Management Base:- 自动SQL计划捕捉
- 成批导入执行计划
自动SQL计划基线捕捉
自动计划捕捉可以通过初始化参数optimizer_use_sql_plan_baselines来开关;当打开了自动计划捕捉时,Oracle会自动将任意重复的SQL语句加载到SPM仓库中;为了识别重复SQL语句,优化器将在语句首次编译时记录每一条SQL语句的id(SQL Signature)到语句日志中 (前面指出的SQL$,SQL$TEXT等基表中)。若这些SQL语句再次被处理(被执行或被编译)时发现其已经存在于语句日志中,则该语句被标示为重复语句(repeatable statement)。相应的Oracle将为该语句创建SQL历史计划,历史计划中包含了足以让优化器再生原执行计划的信息,如SQL text,大纲,绑定变量,编译环境信息等。当前的基于成本的执行计划将被加入到首批的SQL计划基线中,并且这些计划被标记为可接受的(可信任的)。仅有那些可接受的计划会被采用;若未来该SQL语句有了一个新的执行计划,则该执行计划被加入到历史计划中并被标示为已确认的。一个新的SQL计划仅在与SQL计划基线性能进行比较,检验它的性能后,才被认为是可接受的计划。SQL> conn maclean/maclean Connected. SQL> show parameter optimizer NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ optimizer_capture_sql_plan_baselines boolean FALSE optimizer_dynamic_sampling integer 2 optimizer_features_enable string 11.2.0.2 optimizer_index_caching integer 0 optimizer_index_cost_adj integer 100 optimizer_mode string ALL_ROWS optimizer_secure_view_merging boolean TRUE optimizer_use_invisible_indexes boolean FALSE optimizer_use_pending_statistics boolean FALSE optimizer_use_sql_plan_baselines boolean TRUE SQL> alter session set events '10046 trace name context forever,level 1'; Session altered. SQL> alter session set optimizer_capture_sql_plan_baselines=true; Session altered. SQL> select count(object_id) from youyus where object_id between 10 and 1000; COUNT(OBJECT_ID) ---------------- 0 SQL> select count(object_id) from youyus where object_id between 10 and 1000; COUNT(OBJECT_ID) ---------------- 0 SQL> alter session set events '10046 trace name context off'; Session altered. SQL> set autotrace on; SQL> select count(object_id) from youyus where object_id between 10 and 1000; COUNT(OBJECT_ID) ---------------- 0 ........ Note ----- - SQL plan baseline "SQL_PLAN_4km5h6vp5rprm4267f89c" used for this statement /* trace文件显示创建历史计划和SQL计划基线包括以下递归操作 */ SELECT signature FROM sqllog$ WHERE signature = :1 INSERT INTO sqllog$ SELECT :1, 1+TRUNC(sqllog$_seq.nextval/8192) FROM dual MERGE INTO sqlobj$ ...... INSERT INTO sql$ (signature, inuse_features, flags, spare1, spare2) VALUES (:1, :2, :3, null, null) INSERT INTO sql$text (signature, sql_handle, sql_text) VALUES (:1, :2, :3) SQL> exec dbms_stats.gather_table_stats(ownname => 'MACLEAN',tabname => 'YOUYUS',cascade =>true,method_opt => 'for all columns size 254'); PL/SQL procedure successfully completed. SQL> select * from YOUYUS where object_id between 10 and 1000; no rows selected .............................. SQL> alter system flush shared_pool; System altered. SQL> alter session set events '10053 trace name context forever,level 1'; SQL> select * from YOUYUS where object_id between 10 and 1000; no rows selected Note ----- - SQL plan baseline "SQL_PLAN_95dr7p7y4ucm3bd23881d" used for this statement alter session set events '10053 trace name context off'; /* 10053事件的trace内容如下 */ SPM: planId's of plan baseline are: 3173222429 SPM: using qksan to reproduce, cost and select accepted plan, sig = 10571891892567224931 SPM: plan reproducibility round 0 (plan outline + session OFE) SPM: using qksan to reproduce accepted plan, planId = 3173222429 Registered qb: SEL$1 0x90a81b18 (PARSER) ........... ******************************************* Peeked values of the binds in SQL statement ******************************************* Final query after transformations:******* UNPARSED QUERY IS ******* SELECT /*+ INDEX_RS_ASC ("YOUYUS" "OBJD_YOUYUS") */ "YOUYUS"."OWNER" "OWNER","YOUYUS"."OBJECT_NAME" "OBJECT_NAME","YOUYUS"."SUBOBJECT_NAME" "SUBOBJECT_NAME","YOUYUS"."OBJECT_ID" "OBJECT_ID","YOUYUS "."DATA_OBJECT_ID" "DATA_OBJECT_ID","YOUYUS"."OBJECT_TYPE" "OBJECT_TYPE","YOUYUS"."CREATED" "CREATED","YOUYUS"."LAST_DDL_TIME" "LAST_DDL_TIME","YOUYUS"."TIMESTAMP" "TIMESTAMP","YOUYUS"."STATUS" "ST ATUS","YOUYUS"."TEMPORARY" "TEMPORARY","YOUYUS"."GENERATED" "GENERATED","YOUYUS"."SECONDARY" "SECONDARY","YOUYUS"."NAMESPACE" "NAMESPACE","YOUYUS"."EDITION_NAME" "EDITION_NAME" FROM "MACLEAN"."YOUY US" "YOUYUS" WHERE "YOUYUS"."OBJECT_ID">=10 AND "YOUYUS"."OBJECT_ID"<=1000 AND 10<=1000 kkoqbc: optimizing query block SEL$1 (#0) .................. /* 可以看到使用SQL计划基线后,通过plan outline + session OFE信息,优化器reproduce了执行计划 */Figure 1描绘了使用SQL计划基线情况下的SQL编译流程
批量导入
批量导入在数据库升级到11g或部署新的应用时显得特别有用。批量导入(bulk load)可以替代自动捕捉或与自动捕捉协同工作。批量导入的执行计划将被自动接收(automatically accepted)以创建新的SQL计划基线或加入到已有的中。SQL Management Base可以以三种方式批量导入:- 由给定SQL调优集合(SQL Tuning SET STS)生成执行计划
- 使用游标缓存中的执行计划
- 从staging表中将SQL计划基线解压出来
- 在10gr2上创建包含执行计划的STS
- 将STS导入到某张中转表中,并将表上的数据导出到平面文件上
- 将平面文件中的STS数据导入到11g中,并还原为STS
- 使用EM或DBMS_SPM.LOAD_PLANS_FROM_SQLSET存储过程将执行计划导入到SQL Management Base中
- 在源系统中使用DBMS_SPM.CREATE_STGTAB_BASELINE创建中转表(stageing table)
- 使用DBMS_SPM.PACK_STGTAB_BASELINE函数,将SQL计划基线从SMB中导入到中转表上
- 导出中转表数据到平面文件,这一步可以选择使用exp或expdp
- 将平面文件的数据导入到目标系统中,可采用imp或impdp
- 使用DBMS_SPM.UNPACK_STGTAB_BASELINE函数,将SQL计划基线从中转表还原到目标系统的SQL Management Base中
- 仅接受那些性能优于已有计划基线的计划
- 不进行性能验证就接受计划
- 进行性能对比且生成报告,但暂时仍不接受新的计划
使用并管理SQL MANAGEMENT BASE
初始化参数 存在2个控制SPM的初始化参数 optimizer_capture_sql_plan_baselines 控制是否自动为重复的SQL语句捕捉SQL基线计划。在11gR1/R2中默认为false optimizer_use_sql_plan_baselines 控制是否使用SQL基线计划。当被启用时,优化器将会为正在被编译的SQL语句在SQL基线计划中查找合适的可接受计划。若找到,优化器将为每一个SQL基线计划中的执行计划评估成本并采用成本最低的一个。在11gR1/R2中默认为TRUE 管理SQL Management Base的空间使用 SQL语句日志,计划历史以及SQL基线计划都存储在SQL Management Base中。SQL Management Base作为数据库数据字典的一部分,被存放在SYSAUX表空间上。默认情况下SQL Managment Base的空间使用限制是不超过SYSAUX表空间大小的10%。但我们可以有选择地使用DBMS_SPM.CONFIGURE 存储过程在1%-50%之间修改该限制参数。Oracle会在后台每隔一个礼拜检查SMB的空间使用情况,若超出限制则在告警日志中发出警告。同时也会有周度的维护任务会定期清除任何在53周内未被使用的计划。posted on 2010-09-18 18:56 Oracle和MySQL 阅读(512) 评论(0) 编辑 收藏 举报