spm baseline 保持执行计划的稳定性


目前所负责的数据库压力过大,要把其中一个比较核心的SCHEMA迁移到另一套环境里来降低压力。迁移前后的版本是一样的,都是11.1.0.7.统计信息也是通过DBMS_STATS包导出导入的,按理说,执行计划变化的可能性不大。但是为了确保执行计划不出错,打算还是折腾一把,通过11G的 SPM BASELINE在老库生成一个调优集,然后把这个调优集加载到新的数据库上的,然后通过SPM BASELINE提供的过程来为这个调优集里所有的SQL生成BASEINE。这样就能保证这些调优集里的SQL 执行计划不发生变化,而且还可以通过SPM提供的视图来查看那些SQL在新的环境下产生了可以改进的执行计划,如果这种改变是好的,我们可以通过BASELINE重演来接受这种改变。最后可以把没有产生执行计划改变的BAELINE删除掉。具体方案如下:

老库上需要执行的操作:

1)新创建一个SQL 调优集,新创建的调优集是空的,需要通过后续的SQL装载过程来装载SQL.

exec dbms_sqltune.create_sqlset(sqlset_name=>'vodka_set');


2)为新创建的SQL 调优集加载SQL,这里可以选择加载哪些SQL。本例里加载了

  • VODKA 用户产生的
  • 签名不是0的
  • BUFFER_GETS(总)大于1000的
  • 执行次数(总)大于100的
  • 命令类型不为INSERT的SQL
DECLARE
  cur DBMS_SQLTUNE.SQLSET_CURSOR;
BEGIN
  OPEN cur FOR
    SELECT VALUE(P)
      FROM table(DBMS_SQLTUNE.SELECT_CURSOR_CACHE('PARSING_SCHEMA_NAME=''VODKA'' and force_matching_signature<>0 and BUFFER_GETS>1000 and EXECUTIONS>100 and command_type<>2',
                                                  NULL,
                                                  NULL,
                                                  NULL,
                                                  NULL,
                                                  1,
                                                  NULL,
                                                  'ALL')) P;

  DBMS_SQLTUNE.LOAD_SQLSET(sqlset_name     => 'vodka_set',
                           populate_cursor => cur);

END;
/


可以查看SQL 调优集里包含多少SQL

col owner for a20
col name for a20
Select NAME,OWNER,CREATED,STATEMENT_COUNT FROM DBA_SQLSET;

NAME                 OWNER                CREATED             STATEMENT_COUNT
-------------------- -------------------- ------------------- ---------------
vodka_set            SYSTEM               2011-09-25 10:54:41             367


 

3)把调优集的内容加载到一张舞台表里

exec DBMS_SQLTUNE.CREATE_STGTAB_SQLSET('WXH_TBD0931');

exec DBMS_SQLTUNE.PACK_STGTAB_SQLSET('vodka_set','SYSTEM','WXH_TBD0931','SYSTEM');


4)通过导入导出工具来把舞台表传输到新的数据库上

exp system/0o98udrft00oop file=/tmp/weixh.dmp tables=WXH_TBD0931
scp /tmp/[email protected]:/tmp
imp system/0o98udrft00oop file=/tmp/weixh.dmp fromuser=system touser=SYSTEM


新库上需要执行的操作(上面的IMP也是在新库上做的):

5)在新的数据库上把SQL调优集加载进来

begin
  DBMS_SQLTUNE.UNPACK_STGTAB_SQLSET(sqlset_name          => 'vodka_set',
                                    sqlset_owner         => 'SYSTEM',
                                    replace              => true,
                                    staging_table_name   => 'WXH_TBD0931',
                                    staging_schema_owner => 'SYSTEM');
END;
/


6)通过SPM BASELINE的包来把SQL调优集里的SQL都批量的生成BASELINE,这里有一个问题需要注意,有时候你会发现并不是调优集里的每条SQL都能产生BASELINE,这主要是因为,你创建SQL 调优集(第二步)的时候,有些SQL的SQL PLAN已经不存在在共享池里了。

declare
ret number;
begin
ret := dbms_spm.load_plans_from_sqlset(sqlset_name => 'vodka_set',sqlset_owner => 'SYSTEM');
end;
/


这样做了后,就能确保数据库迁移后,两边的执行计划是一致的,不会出现性能问题。如果在新库上,ORACLE认为有更好的执行计划,会在dba_sql_plan_baselines里产生出一个dba_sql_plan_baselines.origin为AUTO-CAPTURE,dba_sql_plan_baselines.ACCEPTED为NO的baseline。我的例子里SQL HANDLE为'SYS_SQL_b13d37f143c8d367'的SQL就产生一个新的不可接受的执行计划。需要等待你的验证。

select sql_handle,plan_name,origin,accepted from dba_sql_plan_baselines where sql_handle='SYS_SQL_b13d37f143c8d367';

SQL_HANDLE                     PLAN_NAME                      ORIGIN                       ACCEPT
------------------------------ ------------------------------ ---------------------------- ------
SYS_SQL_b13d37f143c8d367       SYS_SQL_PLAN_43c8d3671a342c8e  AUTO-CAPTURE                 NO
SYS_SQL_b13d37f143c8d367       SYS_SQL_PLAN_43c8d367affaa175  MANUAL-LOAD                  YES

你可以通过如下两种方法来验证新产生出来的执行计划是否更好。
1)查看两种执行计划的差异来判断

SELECT *
  FROM table(dbms_xplan.display_sql_plan_baseline(sql_handle => 'SYS_SQL_b13d37f143c8d367',
                                                  plan_name  => 'SYS_SQL_PLAN_43c8d3671a342c8e'));
SQL handle: SYS_SQL_b13d37f143c8d367
SQL text: UPDATE APP_USER_LOGIN SET IS_ONLINE = 'y', LAST_REGISTER = :B6 , IP =
          :B5 , ROLE_NAME = :B4 , ORG_ID = :B3 , FALSE_COUNT = 0, CHANNEL = :B2
          WHERE LOGIN_ID = :B1
--------------------------------------------------------------------------------
Plan name: SYS_SQL_PLAN_43c8d3671a342c8e
Enabled: YES     Fixed: NO      Accepted: NO      Origin: AUTO-CAPTURE
--------------------------------------------------------------------------------

Plan hash value: 2701429484

----------------------------------------------------------------------------------------
| Id  | Operation          | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT   |                   |     1 |    72 |     2   (0)| 00:00:01 |
|   1 |  UPDATE            | APP_USER_LOGIN    |       |       |            |          |
|*  2 |   INDEX UNIQUE SCAN| APP_USER_LOGIN_PK |     1 |    72 |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("LOGIN_ID"=:B1)

 

SELECT *
  FROM table(dbms_xplan.display_sql_plan_baseline(sql_handle => 'SYS_SQL_b13d37f143c8d367',
                                                  plan_name  => 'SYS_SQL_PLAN_43c8d367affaa175'));


--------------------------------------------------------------------------------
Plan name: SYS_SQL_PLAN_43c8d367affaa175
Enabled: YES     Fixed: NO      Accepted: YES     Origin: MANUAL-LOAD
--------------------------------------------------------------------------------

Plan hash value: 2066069757

-------------------------------------------------------------------------------------
| Id  | Operation          | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT   |                |     1 |    63 |    15   (0)| 00:00:01 |
|   1 |  UPDATE            | APP_USER_LOGIN |       |       |            |          |
|*  2 |   TABLE ACCESS FULL| APP_USER_LOGIN |     1 |    63 |    15   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("LOGIN_ID"=:B1)


可以看到自动捕获出来的不可接受的BASELINE的执行计划比较优秀,走了索引,因此我们可以通过BASELINE重演接受它,后面会介绍怎么用BASELINE重演

2)重演BASELINE来查看两种执行计划到底哪种更好

SELECT dbms_spm.evolve_sql_plan_baseline(
sql_handle => 'SYS_SQL_b13d37f143c8d367',
plan_name => NULL,
time_limit => 10,
verify => 'yes',
commit => 'no'
)
FROM dual;

DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(SQL_HANDLE=>'SYS_SQL_B13D37F143C8D367',PLAN_NA
--------------------------------------------------------------------------------

-------------------------------------------------------------------------------
                        Evolve SQL Plan Baseline Report
-------------------------------------------------------------------------------

Inputs:
-------
  SQL_HANDLE = SYS_SQL_b13d37f143c8d367
  PLAN_NAME  =
  TIME_LIMIT = 10
  VERIFY     = yes
  COMMIT     = no

Plan: SYS_SQL_PLAN_43c8d3671a342c8e
-----------------------------------
  Plan was verified: Time used .13 seconds.
  Passed performance criterion: Compound improvement ratio >= 115.54

                      Baseline Plan      Test Plan     Improv. Ratio
                      -------------      ---------     -------------
  Execution Status:        COMPLETE       COMPLETE
  Rows Processed:                 1              1
  Elapsed Time(ms):              74             22              3.36
  CPU Time(ms):                  54              6                 9
  Buffer Gets:                  295              2             147.5
  Disk Reads:                   292              2               146
  Direct Writes:                  0              0
  Fetches:                       19              2               9.5
  Executions:                     1              1

-------------------------------------------------------------------------------
                                 Report Summary
-------------------------------------------------------------------------------
Number of SQL plan baselines verified: 1.
Number of SQL plan baselines evolved: 0.

可以看到重演的结果跟以前相比都有大幅度的提升。如果下降,Improv. Ratio会为负值。

如果确定ORACLE自动捕获的产生的SQL BASELINE是好的,那么就可以通过重演来接受它。

SELECT dbms_spm.evolve_sql_plan_baseline(
sql_handle => 'SYS_SQL_b13d37f143c8d367',
plan_name => NULL,
time_limit => 10,
verify => 'yes',
commit => 'yes'
)
FROM dual;


 

至此,这个SQL就接受了这个ORACLE自动产生的BASELINE.

最后,如果觉得必要,可以把执行计划没有发生变化的BASELINE都删除掉。

 

SPM BASELINE的好处是显而易见的:

  • 能够保证迁移后,执行计划不发生变化
  • ORACLE提供了丰富的视图,能够查看哪些SQL在新环境下,ORACLE认为存在更好的执行计划,你可以重演来验证、接受这种改变

如果没有SPM BASELINE,你可能会通过OUTLINE来实现,但是无论如何,OUTLINE的方案可能实现起来要比SPM BASELINE弱的多。因为OUTLINE在新库生成后,你不知道哪些SQL在新环境下产生改变,因此你的OUTLINE也就不敢删除掉,因为一旦删除掉,执行计划可能就有改变。而SPM BASELINE的话,你就能非常清楚,根据SPM提供的视图,能找到哪些BASELINE可以删除掉。对于执行计划发生改变的SQL,也能够根据视图非常轻易的查看,还可以通过重演验证。

总之SPM BASELINE真的是一个数据库升级迁移过程中,保证执行计划稳定的一个非常强大的功能。可惜,只有11G才有。这个方案适合10GR2以上版本升11G。对于9I版本,我后面也会给出方案,敬请期待吧。
 

 

 

 

你可能感兴趣的:(SPM,BASELINE,ORACLE)