ITPub博客

首页 > Linux操作系统 > Linux操作系统 > Oracle中Hint随记

Oracle中Hint随记

原创 Linux操作系统 作者:tthero00boo 时间:2013-07-08 00:51:38 0 删除 编辑
Oracle中Hint随记

1. 优化器:
Oracle的优化器有两种优化方式,即基于规则的优化方式(Rule-Based Optimization,简称为RBO)和基于代价的优化方式(Cost-Based Optimization,简称为CBO),在Oracle8及以后的版本,Oracle强列推荐用CBO的方式
RBO方式:优化器在分析SQL语句时,所遵循的是Oracle内部预定的一些规则。比如我们常见的,当一个where子句中的一列有索引时去走索引。
CBO方式:它是看语句的代价(Cost),这里的代价主要指Cpu和内存。优化器在判断是否用这种方式时,主要参照的是表及索引的统计信息。统计信息给出表的大小、有少行、每行的长度等信息。这些统计信息起初在库内是没有的,是做analyze后才出现的,很多的时候过期统计信息会令优化器做出一个错误的执行计划,因些应及时更新这些信息。
Examda提示:主索引不一定就是优的,比如一个表只有两行数据,一次IO就可以完成全表的检索,而此时走索引时则需要两次IO,这时全表扫描(full table scan)是最好
优化模式包括Rule、Choose、First rows、All rows四种方式:
Rule:基于规则的方式。
Choose:默认的情况下Oracle用的便是这种方式。指的是当一个表或或索引有统计信息,则走CBO的方式,如果表或索引没统计信息,表又不是特别的小,而且相应的列有索引时,那么就走索引,走RBO的方式。
First Rows:它与Choose方式是类似的,所不同的是当一个表有统计信息时,它将是以最快的方式返回查询的最先的几行,从总体上减少了响应时间。
All Rows:也就是我们所说的Cost的方式,当一个表有统计信息时,它将以最快的方式返回表的所有的行,从总体上提高查询的吞吐量。没有统计信息则走RBO的方式。
设定选用哪种优化模式:
A、Instance级别我们可以通过在initSID.ora文件中设定OPTIMIZER_MODE=RULE/CHOOSE/FIRST_ROWS/ALL_ROWS如果没设定OPTIMIZER_MODE参数则默认用的是Choose方式。
B、Sessions级别通过ALTER SESSION SET OPTIMIZER_MODE=RULE/CHOOSE/FIRST_ROWS/ALL_ROWS来设定。
C、语句级别用Hint(/*+ ... */)来设定
为什么表的某个字段明明有索引,但执行计划却不走索引?
1、优化模式是all_rows的方式
2、表作过analyze,有统计信息(最可能的就是统计信息有误)
3、表很小,上文提到过的,Oracle的优化器认为不值得走索引。

2. Hint
人为的干预优化器,按照我们的告诉它的方式生成执行计划。我们可以用Oracle Hints来实现
1) 使用的优化器的类型
2) 基于代价的优化器的优化目标,是all_rows还是first_rows。
3) 表的访问路径,是全表扫描,还是索引扫描,还是直接利用rowid。
4) 表之间的连接类型
5) 表之间的连接顺序
6) 语句的并行程度
除了”RULE”提示外,一旦使用的别的提示,语句就会自动的改为使用CBO优化器,此时如果你的数据字典中没有统计数据,就会使用缺省的统计数据。所以建议大家如果使用CBO或Hints提示,则最好对表和索引进行定期的分析。
如何使用Hints:
Hints只应用在它们所在sql语句块(statement block,由select、update、delete关键字标识)上,对其它SQL语句或语句的其它部分没有影响。如:对于使用union操作的2个sql语句,如果只在一个sql语句上有Hints,则该Hints不会影响另一个sql语句。
我们可以使用注释(comment)来为一个语句添加Hints,一个语句块只能有一个注释,而且注释只能放在SELECT, UPDATE, or DELETE关键字的后面
使用Oracle Hints的语法:
{DELETE|INSERT|SELECT|UPDATE} /*+ hint [text] [hint[text]]... */
or
{DELETE|INSERT|SELECT|UPDATE} --+ hint [text] [hint[text]]...
注解:
1) DELETE、INSERT、SELECT和UPDATE是标识一个语句块开始的关键字,包含提示的注释只能出现在这些关键字的后面,否则提示无效。
2) “+”号表示该注释是一个Hints,该加号必须立即跟在”/*”的后面,中间不能有空格。
3) hint是下面介绍的具体提示之一,如果包含多个提示,则每个提示之间需要用一个或多个空格隔开。
4) text 是其它说明hint的注释性文本
5)使用表别名。如果在查询中指定了表别名,那么提示必须也使用表别名。例如:select /*+ index(e,dept_idx) */ * from emp e;
6)不要在提示中使用模式名称:如果在提示中指定了模式的所有者,那么提示将被忽略。例如:
select /*+ index(scott.emp,dept_idx) */ * from emp
注意:如果你没有正确的指定Hints,Oracle将忽略该Hints,并且不会给出任何错误。

转自:http://czmmiao.iteye.com/blog/1478465

3.oracle hint中ordered 和leading
hash_join可以通过no_swap_join_inputs/swap_join_inputs来强制控制build表,配合leading或者ordered可以控制多表之前的连接顺序。

比如t1,t2,t3,t4共4张表做hash_join
可以通过ordered+no_swap_join_inputs/swap_join_inputs来实现。
比如
如果想实现

( T3 hash-join (T1 hash-join T2)) hash-join T4

t1作为build表和T2做hash_join,然后t3作为build表和t1,t2的结果集作hash_join,在把t3,t1,t2的结果集作build表和t4做hash_join
通过sql可以写为

SQL >select
  2  /*+
  3  ordered
  4  use_hash(t2)
  5  use_hash(t3)
  6  swap_join_inputs(t3)
  7  use_hash(t4)
  8  no_swap_join_inputs(t4)
  9  */
10  * from t1,t2,t3,t4
11  where t1.object_id=t2.object_id
12  and t2.object_name=t3.object_name
13  and t3.owner=t4.owner
14  and t4.owner='MYDB'
15  /
已用时间:  00: 00: 00.07

执行计划
----------------------------------------------------------
Plan hash value: 3494725078

-------------------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |  2137 |   801K|       |   182   (2)| 00:00:03 |
|*  1 |  HASH JOIN           |      |  2137 |   801K|       |   182   (2)| 00:00:03 |
|*  2 |   HASH JOIN          |      |    52 | 14976 |       |   167   (2)| 00:00:03 |
|*  3 |    TABLE ACCESS FULL | T3   |    40 |  3840 |       |    15   (0)| 00:00:01 |
|*  4 |    HASH JOIN         |      | 11651 |  2184K|  1232K|   151   (1)| 00:00:02 |
|   5 |     TABLE ACCESS FULL| T1   | 11651 |  1092K|       |    15   (0)| 00:00:01 |
|   6 |     TABLE ACCESS FULL| T2   | 11652 |  1092K|       |    15   (0)| 00:00:01 |
|*  7 |   TABLE ACCESS FULL  | T4   |    41 |  3936 |       |    15   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

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

   1 - access("T3"."OWNER"="T4"."OWNER")
   2 - access("T2"."OBJECT_NAME"="T3"."OBJECT_NAME")
   3 - filter("T3"."OWNER"='MYDB')
   4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
   7 - filter("T4"."OWNER"='MYDB')

Note
-----
   - dynamic sampling used for this statement
说明:
ordered表示依据from后面写的表的顺序来做联结~
写hints,分开些思路清晰~ ordered后 from t1 ,t2 ,t3 ,t4说明首先使用t1做驱动表来连接t2,如何连接呢?看后面的hint use_hash(t2)
代表连接t2的方式是hash_join;然后用use_hash(t3)表示连接t3的方式是hash-join,那么谁作build表呢?看后面的swap_join_inputs(t3)代表t3作build表和t1-t2的结果集作连接....依此类推~

ordered 是陈旧的hints,leading是用来代替ordered的~ leading不要求sql的写法(from后面的顺序不要求),直接可以在leading中定义连接顺序~
leading和ordered不能一起使用,也没必要一起使用~

针对leading使用:
10g中对leading做了加强~ 可以直接在后面写多表的连接顺序了,也就是说使用leading不需要from后面的固定顺序了
sql >select
  2     /*+
  3     leading(t1 t2 t3 t4)
  4     use_hash(t2)
  5     use_hash(t3)
  6     swap_join_inputs(t3)
  7     use_hash(t4)
  8     no_swap_join_inputs(t4)
  9     */  * from t3,t4,t2,t1
10   where t1.object_id=t2.object_id
11   and t2.object_name=t3.object_name
12   and t3.owner=t4.owner
13   and t4.owner='MYDB'
14  /

SQL >select
  2     /*+
  3     ordered
  4     use_hash(t2)
  5     use_hash(t3)
  6     swap_join_inputs(t3)
  7     use_hash(t4)
  8     no_swap_join_inputs(t4)
  9     */  * from t1,t2,t3,t4
10   where t1.object_id=t2.object_id
11   and t2.object_name=t3.object_name
12   and t3.owner=t4.owner
13   and t4.owner='MYDB'
14  /

转自:http://blog.csdn.net/mantisxf/article/details/5560429

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28859270/viewspace-765700/,如需转载,请注明出处,否则将追究法律责任。

上一篇: ORACLE Hash Join
下一篇: 常用端口说明
请登录后发表评论 登录
全部评论

注册时间:2013-06-30

  • 博文量
    31
  • 访问量
    142120