Oracle - SPM固定执行计划(一)
一、前言生产中偶尔会碰到一些sql,有多种执行计划,其中部分情况是统计信息过旧造成的,重新收集下统计信息就行了。但是有些时候重新收集统计信息也解决不了问题,而开发又在嗷嗷叫,没时间让你去慢慢分析原因的时候,这时临时的解决办法是通过spm去固定一个正确的执行计划,等找到真正原因后再解除该spm。 二、解决办法1. 通过dbms_xplan.display_cursor查看指定sql都有哪些执行计划SQL> select * from table(dbms_xplan.display_cursor(‘&sql_id‘,null,‘TYPICAL PEEKED_BINDS‘));? Enter value for sql_id: 66a4184u0t6hn old 1: select * from table(dbms_xplan.display_cursor(‘&sql_id‘,null,‘TYPICAL PEEKED_BINDS‘)) new 1: select * from table(dbms_xplan.display_cursor(‘66a4184u0t6hn‘,‘TYPICAL PEEKED_BINDS‘)) SQL_ID 66a4184u0t6hn,child number 0 ------------------------------------- select /*for_test*/ * from test1 where object_id = 1 Plan hash value: 4122059633 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 693 (100)| | |* 1 | TABLE ACCESS FULL| TEST1 | 173K| 15M| 693 (1)| 00:00:09 | --------------------------------------------------------------------------- SQL_ID 66a4184u0t6hn,child number 1 ------------------------------------- select /*for_test*/ * from test1 where object_id = 1 Plan hash value: 2214001748 ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| TEST1 | 11 | 1056 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_TEST1 | | | 1 (0)| 00:00:01 | ----------------------------------------------------------------------------------------- ? 2. 查询该sql的历史执行情况SQL> col snap_id for 99999999??????????????????????????????????????????????????????????????????????????????????? Enter value for sql_id: 66a4184u0t6hn old 16: and sql_id = trim(‘&sql_id‘) order by s.snap_id desc) new 16: and sql_id = trim(‘66a4184u0t6hn‘) order by s.snap_id desc) SNAP_ID DATE_TIME PLAN_HASH EXECUTIONS etime/exec buffer/exec diskread/exec cputim/exec rows/exec --------- ------------------------------ ----------- ---------- ----------- ------------ ------------- ----------- --------- 39 08/16/19_1500_1600 2214001748 1 .12 25839 2901 .10 173927 39 08/16/19_1500_1600 4122059633 3 .11 13992 847 .11 173927 3. 绑定执行计划从前两步中可以看到该sql有两条执行计划,假如plan_hash_value为’2214001748’才是对的,而此时数据库选择的是另一条执行计划,我们可以通过执行以下function去将执行计划固定为我们想要的。 三、做个实验1. 准备测试表实验环境,使用scott账号,并给scott赋予dba权限 SQL> create table test1 as select * from dba_objects; SQL> select object_id,count(*) from test1 group by object_id; OBJECT_ID COUNT(*) ---------- ---------- 1 173927 82112 1 82121 1 82118 1 82119 1 82122 1 82113 1 82114 1 82120 1 82115 1 82116 1 82117 1 ? 2. 创建索引并收集统计信息SQL> create index idx_test1 on test1(object_id) online; SQL> begin ? 3. 通过修改优化器模式,模拟同样的sql产生两条不同的执行计划开启一个窗口A Execution Plan ---------------------------------------------------------- Plan hash value: 4122059633 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 173K| 15M| 693 (1)| 00:00:09 | |* 1 | TABLE ACCESS FULL| TEST1 | 173K| 15M| 693 (1)| 00:00:09 | --------------------------------------------------------------------------- ? 开启另一个窗口B Execution Plan ---------------------------------------------------------- Plan hash value: 2214001748 ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 11 | 1056 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| TEST1 | 11 | 1056 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_TEST1 | | | 1 (0)| 00:00:01 | ----------------------------------------------------------------------------------------- ? 再开启一个窗口C SQL_ID SQL_TEXT OPTIMIZER_ PLAN_HASH_VALUE CHILD_NUMBER ------------- ------------------------------------------------------- ---------- --------------- ------------ 66a4184u0t6hn select /*for_test*/ * from test1 where object_id = 1 ALL_ROWS 4122059633 0 66a4184u0t6hn select /*for_test*/ * from test1 where object_id = 1 FIRST_ROWS 2214001748 1 ? 可以看到,因为优化器模式的不同,相同的sql产生了两条截然不同的执行计划 ? 4. 绑定执行计划再新开一个窗口D,执行 Execution Plan ---------------------------------------------------------- Plan hash value: 4122059633 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 173K| 15M| 693 (1)| 00:00:09 | |* 1 | TABLE ACCESS FULL| TEST1 | 173K| 15M| 693 (1)| 00:00:09 | ---------------------------------------------------------------------------
通过执行以下function去将执行计划固定为索引扫描 再执行以下sql Execution Plan ---------------------------------------------------------- Plan hash value: 2214001748 ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 11 | 1056 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| TEST1 | 11 | 1056 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_TEST1 | 173K| | 1 (0)| 00:00:01 | ----------------------------------------------------------------------------------------- Note ----- - SQL plan baseline "SQL_PLAN_9657urkb9u2tnf24a05ff" used for this statement
当我们找到sql执行计划突变的原因了,解决问题之后,就可以删除spm了。如何删除spm呢? 新开窗口E SQL_HANDLE PLAN_NAME ORIGIN ------------------------------ ------------------------------ -------------- SQL_9314fabc969d0b34 SQL_PLAN_9657urkb9u2tnf24a05ff MANUAL-LOAD SQL_9314fabc969d0b34 SQL_PLAN_9657urkb9u2tnfe026eff AUTO-CAPTURE ? 可以看到该sql有两条PLAN_NAME,一个是系统自动捕获的,一个是我们手工绑定的,反正我们不再需要这个了,统统删除 查看当前sql的执行计划基线 再在窗口D中执行以下sql Execution Plan ---------------------------------------------------------- Plan hash value: 4122059633 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 173K| 15M| 693 (1)| 00:00:09 | |* 1 | TABLE ACCESS FULL| TEST1 | 173K| 15M| 693 (1)| 00:00:09 | ---------------------------------------------------------------------------
? 五、说明文章例子整理于《基于oracle的sql优化》,后面将写另一个场景,就是如果系统里就一个执行计划,但是该执行计划是有问题的,如何去手工生成一个正确的执行计划,然后绑定。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |