执行计划保留在stored outline中,一个outline是一系列与sql语句相关的优化器hints,如果语句的outline被启用了,oracle自动考虑存放的hints,并试着产生一个与这些hints相关的执行计划。
oracle可以为一个sql或是所有的sql语句产生一个公共的或私有的stored outline。你可以将outline分组并控制oracle使用哪组outline,减少了管理和部署的工作。
oracle在sys表空间中创建了user_outlines和useroiutline_hits视图,这两个视图是基于ol$和ol$hints表的。
oracle存放outline数据在ol$,ol$hints和ol$nodes表中。会一直保存,除非你删除。
启用固定计划
为了使outline能正常使用,需要设置下面的参数
query_rewrite_enabled
start_transformation_enabled
optimizer_features_enable
dbms_outln和dbms_outln_edit包用来提供存储过程来管理outline和他的分类。
一些有用的dbms_outln和dbms_outln_edit存储过程有下面的:
clear_used--清除具体的outline
drop_by_cat清除指定类别的outline
update_by_cat更新指定的类别到别的类别
exact_text_signatures根据具体文本计算outline的签名
generate_signature-为具体的sql文本生成签名。
oracle可以自动为所有的sql生成outline,也可以为具体的sql生成。当你设置了参数create_stored_outlines=true的时候,oralce会自动生成outline。要想为指定的sql生成outline,你需要使用create outline语句。
当创建或编辑一个私有outline的时候,这个outline的数据是在system用户下面的。可以再使用create outline的时候指定具体的类别,不指定的话,就是默认的类别了。
当oracle在编译sql的时候,为了使用存储outline,设置参数use_sotred_outlines=true。这样oracle使用默认类别。如果使用use_stored_outlines参数指定了一个类别,那么oracle使用那个类别直到你改变成别的类别。如果在你指定的类别中oracle没有找到匹配 的outline,那么oracle去默认的类别中取查找。
要是想要使用具体的outline,而不是所有的outline,使用alter outline语句来启用具体outline.要是想要使用类别中的outline,而不是一个具体的outline,使用alter outline来禁用具体的outline。alter outline也可以重命名一个outline,重新分配到别的类别,或重新生成它。
use_private_outlines参数让你控制私有的outline.一个私有的outline只能在当前会话中被看见,并且它的数据存放在当前解析模式下面。
通过直接调整outline,就可以不用修改应用程序来调优sql了。
当use_private_outlines参数被启用,sql语句被执行的时候,优化器在会话私有区域获取outline,而不是公共区域,如果在私有区域没有,那么优化器不会使用outline来编译语句。
任何的create outline语句需要create any outline权限。指定from子句也需要select权限。当开始编辑,ue_private_outlines应该设置成outline所属的类别,编辑完成后,这个参数在设置回false来存放会话到正常outline。
下面是一个编辑outline的例子
假如要编辑oll
1连接到用户
2使用下面的语句克隆outline到私有区
create private outline p_oll from oll;
3编辑outline,使用em或dbms_outln_edit
4如果手工编辑outline,使用dbms_outlin_edit.change_join_pos来改变位置,然后同步outline定义使用下面的语句
exec dbms_outln_edit.refresh_private_outline('S-LL');
create private outline p_oll from pivate p_oll;
5测试编辑。使用use_private_outlines=true,运行explain plan
6如果要保存这些编辑给公共使用,执行下面的语句
create or replace outline oll from private p_oll;
7禁用私有outline
use_private_outlines=false;
怎么看一个outline在被使用
查看v$sql的outline_category和outline_sid列。如果outline_category是null,那么就没有使用outline,如果使用了,那么这列就是显示的类别。outline_sid要是0那么就说明是一个公共outline,要是会话id,那么就是私有outline
SELECT OUTLINE_CATEGORY, OUTLINE_SID
FROM V$SQL
WHERE SQL_TEXT LIKE 'SELECT COUNT(*) FROM emp%';
查看outline数据
SELECT NAME, SQL_TEXT
FROM USER_OUTLINES
WHERE CATEGORY='mycat';
SELECT HINT
FROM USER_OUTLINE_HINTS
WHERE NAME='name1';
SELECT NAME, CATEGORY, ENABLED FROM USER_OUTLINES;
创建outline的例子
1CREATE OUTLINE salaries FOR CATEGORY special
ON SELECT last_name, salary FROM employees;
2创建一个私有克隆outline
EXECUTE DBMS_OUTLN_EDIT.CREATE_EDIT_TABLES; CREATE OR REPLACE PRIVATE OUTLINE my_salaries FROM salaries;
3将私有outline发布到公共区
CREATE OR REPLACE OUTLINE public_salaries
FROM PRIVATE my_salaries;
outline测试
SQL> begin
2 for i in 1 .. 10000 loop
3 insert into test(owner,object_name,created,last_ddl_time,object_id) values(
'bai','t',sysdate,sysdate,50);
4 end loop;
5 end;
6 /
PL/SQL 过程已成功完成。
SQL> commit;
提交完成。
SQL> select count(*) from test;
COUNT(*)
----------
10049
SQL> create outline ol on select * from test where object_id=50;
create outline ol on select * from test where object_id=50
*
第 1 行出现错误:
ORA-18004: 大纲已存在
SQL> drop outline ol;
大纲已删除。
SQL> create outline ol on select * from test where object_id=50;
大纲已创建。
SQL> alter system set use_stored_outlines=ol;
系统已更改。
SQL> set autot trace
SQL> select * from test where object_id=50;
已选择10001行。
执行计划
----------------------------------------------------------
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 384 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TEST | 3 | 384 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=50)
Note
-----
- outline "OL" used for this statement
统计信息
----------------------------------------------------------
38 recursive calls
123 db block gets
725 consistent gets
0 physical reads
568 redo size
145854 bytes sent via SQL*Net to client
7711 bytes received via SQL*Net from client
668 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
10001 rows processed
SQL> set autot off
SQL> delete test where object_id=50;
已删除10001行。
SQL> commit;
提交完成。
SQL> set autot trace
SQL> select * from test where object_id=50;
未选定行
执行计划
----------------------------------------------------------
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 384 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TEST | 3 | 384 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"=50)
Note
-----
- outline "OL" used for this statement
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
53 consistent gets
0 physical reads
0 redo size
992 bytes sent via SQL*Net to client
374 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
SQL>
SQL> alter system set use_stored_outlines=false;
系统已更改。
SQL> select * from test where object_id=50;
未选定行
执行计划
----------------------------------------------------------
Plan hash value: 3945961961
--------------------------------------------------------------------------------
------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
|
--------------------------------------------------------------------------------
------
| 0 | SELECT STATEMENT | | 1 | 128 | 1 (0)| 00:0
0:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 128 | 1 (0)| 00:0
0:01 |
|* 2 | INDEX RANGE SCAN | I_TEST | 1 | | 1 (0)| 00:0
0:01 |
--------------------------------------------------------------------------------
------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"=50)
Note
-----
- dynamic sampling used for this statement
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
31 consistent gets
0 physical reads
0 redo size
992 bytes sent via SQL*Net to client
374 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
SQL>