什么是Hint
Hint 是 Oracle 提供的一种 SQL 语法,它允许用户在 SQL 语句中插入相关的语法,从而影响 SQL 的执行方式。
因为 Hint 的特殊作用,所以对于开发人员不应该在代码中使用它,Hint 更像是 Oracle 提供给 DBA 用来分析诊断问题的工具 。
导致 Hint 失效的原因
在使用 Hint 时需要注意的一点是,并非任何时刻 Hint 都起作用。 导致 HINT 失效的原因有如下 2 点:
(1) 如果 CBO 认为使用 Hint 会导致错误的结果时,Hint 将被忽略。
(2) 如果表中指定了别名,那么 Hint 中也必须使用别名,否则 Hint 也会忽略。
SQL>Select /*+full(a)*/ * from t a; -- 使用 hint
SQL>Select /*+full(t) */ * from t a; --不使用 hint
Hint 使用规则及注意事项
1、hint 其实是一种注释,如果目标 SQL 的文本出现了 hint,则优化器会选择 hint 的执行计划,而不会考虑
最优的执行计划,但前提是这个 HINT 是可选的执行计划之一。
2、hint 的用法:必须紧随关键字 select、insert、update,delete 后,hint 中第一个星号和加号之间不能有空格,一般写法 /*+ gather_plan_statistics */,如果有两个 hint,用空格隔开。hint 中指定具体对象时,不能带上该对象所在 schema 的名称。即使该 sql 文本中已经有对应的 schema的名称。
在 hint 中指定具体表名时,如果该表在对应 sql 文本中有别名,则应该使用该表的别名。oracle 数据库中的query block 是指一个语义上完整的查询语句,hint 生效范围仅限于它本身所在的 query block。如果一个语句有子查询,那么主查询的 hint 只能作用于主查询,如果想让 Hint 作用于子查询,那么 hint 要加在子查询上。
Hint 的功能划分
可以分成如下几类:
Hint使用示例
1、和优化器相关的 Hint
SQL> select /*+ all_rows */ * from scott.emp;
SQL> select /*+ first_rows(20) */ * from scott.emp;
SQL> select /*+ rule */ * from scott.emp;
2、访问路径相关的 Hint
这一部分 hint 将直接影响 SQL 的执行计划,所以在使用时需要特别小心。 该类 Hint 对 DBA 分析 SQL 性能
非常有帮助,DBA 可以让 SQL 使用不同的 Hint 得到不同的执行计划,通过比较不同的执行计划来分析当前 SQL性能。
FULL Hint
该 Hint 告诉优化器对指定的表通过全表扫描的方式访问数据。
示例:
SQL> select /*+full(emp) */ * from emp;
要注意,如果表有别名,在 hint 里也要用别名, 这点在前面已经说明。
INDEX Hint
Index hint 告诉优化器对指定的表通过索引的方式访问数据,当访问索引会导致结果集不完整时,优化器会忽略这个 Hint。
示例:
SQL> select /*+index(emp index_emp) */ * from emp where id>1;
谓词里有索引字段,才会用索引。
NO_INDEX Hint
No_index hint 告诉优化器对指定的表不允许使用索引。
示例:
SQL> select /*+no_index(emp index_emp) */ * from emp where id>1;
INDEX_DESC Hint
该 Hint 告诉优化器对指定的索引使用降序方式访问数据,当使用这个方式会导致结果集不完整时,优化器将忽略这个索引。
示例:
SQL> select /*+index_desc(emp index_emp) */ * from emp where id>1;
INDEX_COMBINE Hint
该 Hint 告诉优化器强制选择位图索引,当使用这个方式会导致结果集不完整时,优化器将忽略这个 Hint。
示例:
SQL> select /*+ index_combine(emp index_bm) */ * from emp;
INDEX_FFS Hint
该 hint 告诉优化器以 INDEX_FFS(INDEX Fast Full Scan)的方式访问数据。当使用这个方式会导致结果集不完整时,优化器将忽略这个 Hint。
示例:
SQL> select /*+ index_ffs(emp index_emp) */ id from emp where id>0;
INDEX_JOIN Hint
索引关联,当谓词中引用的列上都有索引时,可以通过索引关联的方式来访问数据。
示例:
SQL> select /*+ index_join(emp index_emp index_bm) */ * from emp where id>0 and name='tom ';
INDEX_SS Hint
该 Hint 强制使用 index skip scan 的方式访问索引,从 Oracle 9i 开始引入这种索引访问方式,当在一个联合索引中,某些谓词条件并不在联合索引的第一列时(或者谓词并不在联合索引的第一列时),可以通过 index
skip scan 来访问索引获得数据。 当联合索引第一列的唯一值很小时,使用这种方式比全表扫描效率要高。当
使用这个方式会导致结果集不完整时,优化器将忽略这个 Hint。
示例:
SQL> select /*+ index_ss(emp index_union) */ * from emp where id>0;
3、表关联顺序的 Hint
LEADING hint
在一个多表关联的查询中,该 Hint 指定由哪个表作为驱动表,告诉优化器首先要访问哪个表上的数据。
示例:
SQL> select /*+leading(t1,t) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;
SQL> select /*+leading(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Ti
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 812 | 6 (17)| 00
| 1 | MERGE JOIN | | 14 | 812 | 6 (17)| 00
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 80 | 2 (0)| 00
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00
|* 4 | SORT JOIN | | 14 | 532 | 4 (25)| 00
| 5 | TABLE ACCESS FULL | EMP | 14 | 532 | 3 (0)| 00
--------------------------------------------------------------------------------
ORDERED Hint
该 hint 告诉 Oracle 按照 From 后面的表的顺序来选择驱动表,Oracle 建议在选择驱动表上使用 Leading,它更灵活一些。
SQL> select /*+ordered */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;
4、表关联操作的 Hint
USE_HASH,USE_NL,USE_MERGE hint
这三种关联方式是多表关联中主要使用的关联方式。 通常来说,当两个表都比较大时,Hash Join 的效率要高于嵌套循环(nested loops)的关联方式。
Hash join 的工作方式是将一个表(通常是小一点的那个表)做 hash 运算,将列数据存储到 hash 列表中,从另一个表中抽取记录,做 hash 运算,到 hash 列表中找到相应的值,做匹配。
Nested loops 工作方式是从一张表中读取数据,访问另一张表(通常是索引)来做匹配,nested loops 适用的场合是当一个关联表比较小的时候,效率会更高。
Merge Join 是先将关联表的关联列各自做排序,然后从各自的排序表中抽取数据,到另一个排序表中做匹配,因为 merge join 需要做更多的排序,所以消耗的资源更多。 通常来讲,能够使用 merge join 的地方,hash
join 都可以发挥更好的性能。
USE_HASH,USE_NL,USE_MERGE 这三种hint 就是告诉优化器使用哪种关联方式。
示例如下:
SQL> select /*+use_hash(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;
SQL> select /*+use_nl(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;
SQL> select /*+use_merge(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;
NO_USE_HASH,NO_USE_NL,NO_USE_MERGE HINT
分别禁用对应的关联方式。
示例:
SQL> select /*+no_use_merge(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;
SQL> select /*+no_use_nl(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;
SQL> select /*+no_use_hash(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;
5、并行执行相关的 Hint
PARALLEL HINT
指定 SQL 执行的并行度,这个值会覆盖表自身设定的并行度,如果这个值为 default,CBO 使用系统参数值。
示例:
SQL> select /*+parallel(t 4) */ * from scott.dept t;
NO_PARALLEL HINT
在 SQL 中禁止使用并行。
示例:
SQL> select /*+ no_parallel(t) */ * from scott.dept t;
6、其他方面的一些 Hint
APPEND HINT
提示数据库以直接加载的方式(direct load)将数据加载入库。
示例:
Insert /*+append */ into t as select * from all_objects;
这个 hint 用的比较多。 尤其在插入大量的数据,一般都会用此 hint。
DYNAMIC_SAMPLING HINT
提示 SQL 执行时动态采样的级别。 这个级别从 0-10,它将覆盖系统默认的动态采样级别。
示例:
SQL> select /*+ dynamic_sampling(t 2) */ * from scott.emp t where t.empno>0;