您的位置:首页 > 数据库 > Oracle

oracle 11G 执行计划管理

2016-10-11 17:38 441 查看
一、oracle 11G 执行计划管理原理

oracle11G开始,引入了sql执行计划管理(SQL Plan Management)这个新特性

通过启用该特性,某条语句如果产生了一个新的执行计划,只有在它的性能比原来的执行计划好的情况下,才会被使用。

优化器维护两个列表:

plan history

plan baseline

11G也支持手工维护plan history,作为对自动维护plan history的功能补充

plan baseline是plan history的一个子集

1.初始化参数 OPTIMIZER_CAPTURE_PLAN_BASELINES 设置为true,则会自动捕获SQL的执行计划。

SQL第一次执行,plan history和plan baseline列表都为空,这时产生的执行计划会同时进入到plan history,plan baseline列表中

以后同一语句所产生的新执行计划都会先进入到plan history中,然后同plan baseline中的执行计划进行比较,只有成本比plan baseline

中的要低才会进入到plan baseline中

2.使用dbms_spm包手工处理,这可以让你手工管理SQL Plan baseline。使用该包,你可以直接将SQL的执行计划从 shared pool里加载到

plan baseline里,也可以将已经存在的SQL Tuning Set加载到plan baseline里。同时,dbms_spm还可以将plan history里的执行计划加入到

plan baseline里。反之也可以用该包将plan baseline里的执行计划移出去。

3.plan baseline 里的执行计划是如何被使用的呢?

oracle 提供了一个初始化参数:OPTIMIZER_USE_PLAN_BASELINES,该参数缺省为true,表示要求优化器考虑使用plan baseline里的执行计划,

每次优化器解析SQL语句的时候,首先仍然使用11G之前的传统方式产生一个成本最低的执行计划,然后看初始化参数:

OPTIMIZER_USE_PLAN_BASELINES是否设置为true,如果为false,则直接返回所生成的执行计划。否则如果为true,则去plan_history里找是否存在

相同的执行计划,如果找到,则再去plan baseline里找是否存在相同的执行计划,如果也找到了,则直接返回该执行计划。如果在plan_history里没找到

相同的执行计划,则将生成的执行计划加入到plan history里,然后将执行计划与plan baseline里已经存在的进行比较,看哪个成本低就选取哪个执行计划

SQL语句的plan history以及plan baseline所涉及到的表是存放在SQL Management Base (SMB)里的,SMB里同样也存放了SQL Profiles。而SMB是数据字典的一部分,存放在SYSAUX表空间里。SMB所占用的空间会自动定期的删除。

二、执行计划管理的测试

oracle11g提供了一个视图:dba_sql_plan_baselines,可以在该视图里查询某条 SQL语句相关的plan history以及plan baseline。我们来看下面的例子

首先创建一个测试表.

SQL> create table t1(skew number,padding varchar2(100));

Table created.

SQL>
SQL> insert into t1 select rownum,object_name from dba_objects;

86632 rows created.

SQL> commit;
SQL> set autot trace exp stat
SQL> select * from t1 where skew=200;

Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013

--------------------------------------------------------------------------
| Id  | Operation	  | Name | Rows  | Bytes | Cost (%CPU)| Time	 |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |	 |     5 |   325 |   116   (1)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| T1	 |     5 |   325 |   116   (1)| 00:00:02 |
--------------------------------------------------------------------------

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

1 - filter("SKEW"=200)

Note
-----
- dynamic sampling used for this statement (level=2)

Statistics
----------------------------------------------------------
10  recursive calls
0  db block gets
497  consistent gets
0  physical reads
0  redo size
607  bytes sent via SQL*Net to client
524  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
2  sorts (memory)
0  sorts (disk)
1  rows processed

SQL> /

Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013

--------------------------------------------------------------------------
| Id  | Operation	  | Name | Rows  | Bytes | Cost (%CPU)| Time	 |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |	 |     5 |   325 |   116   (1)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| T1	 |     5 |   325 |   116   (1)| 00:00:02 |
--------------------------------------------------------------------------

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

1 - filter("SKEW"=200)

Note
-----
- dynamic sampling used for this statement (level=2)

Statistics
----------------------------------------------------------
0  recursive calls
0  db block gets
423  consistent gets
0  physical reads
0  redo size
607  bytes sent via SQL*Net to client
524  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
SQL> select * from dba_sql_plan_baselines;

no rows selected


尽管执行两次,但是这时去查询dba_sql_plan_baselines,试图找到SQL文本为select * from t1 where skew=200的记录时,会发现没有记录,因为

optimizer_capture_sql_plan_baselines缺省为false。我们将该参数设置为true以后继续测试。

SQL> alter session set optimizer_capture_sql_plan_baselines=true;

Session altered.

SQL> select * from t1 where skew=200;

SKEW
----------
PADDING
--------------------------------------------------------------------------------
200
I_SQL$TEXT_PKEY

SQL> /

SKEW
----------
PADDING
--------------------------------------------------------------------------------
200
I_SQL$TEXT_PKEY

SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,autopurge from dba_sql_plan_baselines where sql_text like 'select * from t1 where skew=200';

SIGNATURE
----------
SQL_HANDLE
--------------------------------------------------------------------------------
PLAN_NAME
--------------------------------------------------------------------------------
ORIGIN					   ENABLED   ACCEPTED  AUTOPURGE
------------------------------------------ --------- --------- ---------
1.2376E+19
SQL_abc0a2c042fa089c
SQL_PLAN_arh52s11gn24wdbd90e8e
AUTO-CAPTURE				   YES	     YES       YES


我们可以看到,文本为"select * from t1 where skew=200"的SQL语句在plan history里产生了一个执行计划。其中,
sql_handle表示SQL语句的句柄;

plan_name则表示SQL执行计划的名字;

origin表示该执行计划是如何进入到plan_history的,该列值为AUTO-CAPTURE,则说明是由优化器自动加入的,

如果是MANUAL则说明是由DBA手工加入的;

enabled表示是否被启用了;如果某个执行计划为禁用,则优化器根本就不会考虑使用该计划;

accepted表示是否接受,也就是是否进入了plan baseline。

autopurge表示是否为定期自动删除。

我们继续测试,在skew列上添加一个索引,从而让原来的SQL不走全表扫描,而改走索引扫描。

SQL> create index idx_skew on t1(skew);

Index created.
SQL> exec dbms_stats.gather_table_stats('SYS','T1',cascade=>true);

PL/SQL procedure successfully completed.

SQL> select * from t1 where skew=200;

SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge from dba_sql_plan_baselines where sql_text like 'select * from t1 where skew=200';

SIGNATURE SQL_HANDLE										      PLAN_NAME 									     ORIGIN 				    ENABLED   ACCEPTED	FIXED	  AUTOPURGE
---------- ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ ------------------------------------------ --------- --------- --------- ---------
1.2376E+19 SQL_abc0a2c042fa089c 								      SQL_PLAN_arh52s11gn24w22142e90							     AUTO-CAPTURE				    YES       NO	NO	  YES
1.2376E+19 SQL_abc0a2c042fa089c 								      SQL_PLAN_arh52s11gn24wdbd90e8e							     AUTO-CAPTURE				    YES       YES	NO	  YES


这时我们可以看到,dba_sql_plan_baselines视图里多了一个执行计划,也就是我们后面那个使用了索引扫描的执行计划。而该执行计划的accepted为NO,说明该计划并没有

进入到plan baseline里,但进入了plan history里。

这时我们可以通过调用dbms_spm包来手工将走索引的执行计划加入到plan baseline里。如下所示,将accepted改为YES。

执行DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE前:

SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge from dba_sql_plan_baselines where plan_name='SQL_PLAN_arh52s11gn24w22142e90';

SIGNATURE SQL_HANDLE										      PLAN_NAME 									     ORIGIN 				    ENABLED   <span style="color:#ff0000;">ACCEPTED	</span>FIXED	  AUTOPURGE
---------- ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ ------------------------------------------ --------- --------- --------- ---------
1.2376E+19 SQL_abc0a2c042fa089c 								      SQL_PLAN_arh52s11gn24w22142e90							     AUTO-CAPTURE				    YES       <span style="color:#ff0000;">NO	</span>NO	  YES


执行DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE后:
SQL> declare
l_plans_altered clob;
begin
l_plans_altered := DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(sql_handle => 'SQL_abc0a2c042fa089c',
plan_name  => 'SQL_PLAN_arh52s11gn24w22142e90',
time_limit => DBMS_SPM.AUTO_LIMIT,
verify     => 'yes',
commit     => 'yes');
end;  2    3    4    5    6    7    8    9
10  /

PL/SQL procedure successfully completed.

SQL>
SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge from dba_sql_plan_baselines where plan_name='SQL_PLAN_arh52s11gn24w22142e90';

SIGNATURE SQL_HANDLE										      PLAN_NAME 									     ORIGIN 				    ENABLED   <span style="color:#ff0000;">ACCEPTED	</span>FIXED	  AUTOPURGE
---------- ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ ------------------------------------------ --------- --------- --------- ---------
1.2376E+19 SQL_abc0a2c042fa089c 								      SQL_PLAN_arh52s11gn24w22142e90							     AUTO-CAPTURE				    YES       <span style="color:#ff0000;">YES</span>	NO	  YES

SQL>


不过后来发现,要把accepted变为NO却是不可以了,只有先删除,然后再重新生成让优化器自动加入到plan history中

SQL> DECLARE
l_plans_dropped PLS_INTEGER;
BEGIN
l_plans_dropped := DBMS_SPM.drop_sql_plan_baseline(sql_handle => 'SQL_abc0a2c042fa089c',
plan_name  => 'SQL_PLAN_arh52s11gn24w22142e90');
end;  2    3    4    5    6
7  /

PL/SQL procedure successfully completed.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: