老库上需要执行的操作:
1)新创建一个SQL 调优集,新创建的调优集是空的,需要通过后续的SQL装载过程来装载SQL.
exec dbms_sqltune.create_sqlset(sqlset_name=>'vodka_set');
2)为新创建的SQL 调优集加载SQL,这里可以选择加载哪些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的好处是显而易见的:
如果没有SPM BASELINE,你可能会通过OUTLINE来实现,但是无论如何,OUTLINE的方案可能实现起来要比SPM BASELINE弱的多。因为OUTLINE在新库生成后,你不知道哪些SQL在新环境下产生改变,因此你的OUTLINE也就不敢删除掉,因为一旦删除掉,执行计划可能就有改变。而SPM BASELINE的话,你就能非常清楚,根据SPM提供的视图,能找到哪些BASELINE可以删除掉。对于执行计划发生改变的SQL,也能够根据视图非常轻易的查看,还可以通过重演验证。
总之SPM BASELINE真的是一个数据库升级迁移过程中,保证执行计划稳定的一个非常强大的功能。可惜,只有11G才有。这个方案适合10GR2以上版本升11G。对于9I版本,我后面也会给出方案,敬请期待吧。