Oracle中Hint深入理解

来源:互联网 发布:我的世界pe我是僵尸js 编辑:程序博客网 时间:2024/06/04 18:30

Oracle中Hint深入理解(原创)

    博客分类:
  • Oracle Tuning
 

Hint概述
基于代价的优化器是很聪明的,在绝大多数情况下它会选择正确的优化器,减轻了DBA的负担。但有时它也聪明反被聪明误,选择了很差的执行计划,使某个语句的执行变得奇慢无比。

此时就需要DBA进行人为的干预,告诉优化器使用我们指定的存取路径或连接类型生成执行计划,从而使语句高效的运行。例如,如果我们认为对于一个特定的语句,执行全表扫描要比执行索引扫描更有效,则我们就可以指示优化器使用全表扫描。在Oracle中,是通过为语句添加 Hints(提示)来实现干预优化器优化的目的。
不建议在代码中使用hint,在代码使用hint使得CBO无法根据实际的数据状态选择正确的执行计划。毕竟
数据是不断变化的,10g以后的CBO也越来越完善,大多数情况下我们该让Oracle自行决定采用什么执行计划。

Oracle Hints是一种机制,用来告诉优化器按照我们的告诉它的方式生成执行计划。我们可以用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,并且不会给出任何错误。
hint被忽略

如果CBO认为使用hint会导致错误的结果时,hint将被忽略,详见下例
SQL> select /*+ index(t t_ind) */ count(*) from t;
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
-------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Cost (%CPU)| Time     |
-------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    57   (2)| 00:00:01 |
|   1 |  SORT AGGREGATE    |      |     1 |            |          |
|   2 |   TABLE ACCESS FULL| T    | 50366 |    57   (2)| 00:00:01 |
-------------------------------------------------------------------

因为我们是对记录求总数,且我们并没有在建立索引时指定不能为空,索引如果CBO选择在索引上进行count时,但索引字段上的值为空时,结果将不准确,故CBO没有选择索引。
SQL>  select /*+ index(t t_ind) */ count(id) from t;
Execution Plan
----------------------------------------------------------
Plan hash value: 646498162
--------------------------------------------------------------------------
| Id  | Operation        | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT |       |     1 |     5 |   285   (1)| 00:00:04 |
|   1 |  SORT AGGREGATE  |       |     1 |     5 |            |          |
|   2 |   INDEX FULL SCAN| T_IND | 50366 |   245K|   285   (1)| 00:00:04 |
--------------------------------------------------------------------------

因为我们只对id进行count,这个动作相当于count索引上的所有id值,这个操作和对表上的id字段进行count是一样的(组函数会忽略null值)

Hint的具体用法

和优化器相关的hint

1、/*+ ALL_ROWS */
表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化.
SELECT /*+ ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';
2、/*+ FIRST_ROWS(n) */
表明对语句块选择基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化.
SELECT /*+FIRST_ROWS(20) */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';
3、/*+ RULE*/
表明对语句块选择基于规则的优化方法.
SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';
和访问路径相关的hint

1、/*+ FULL(TABLE)*/
表明对表选择全局扫描的方法.
SELECT /*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO='SCOTT';
2、/*+ INDEX(TABLE INDEX_NAME) */
表明对表选择索引的扫描方法.
SELECT /*+INDEX(BSEMPMS SEX_INDEX) */ * FROM BSEMPMS WHERE SEX='M';
5、/*+ INDEX_ASC(TABLE INDEX_NAME)*/
表明对表选择索引升序的扫描方法.
SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ * FROM BSEMPMS WHERE DPT_NO='SCOTT';
6、/*+ INDEX_COMBINE*/
为指定表选择位图访问路经,如果INDEX_COMBINE中没有提供作为参数的索引,将选择出位图索引的布尔组合方式.
SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI) */  * FROM BSEMPMS
WHERE SAL<5000000 AND HIREDATE

7、/*+ INDEX_JOIN(TABLE INDEX_NAME1 INDEX_NAME2) */
当谓词中引用的列都有索引的时候,可以通过指定采用索引关联的方式,来访问数据
select /*+ index_join(t t_ind t_bm) */ id from t where id=100 and object_name='EMPLOYEES'
8、/*+ INDEX_DESC(TABLE INDEX_NAME)*/
表明对表选择索引降序的扫描方法.

SELECT /*+INDEX_DESC(BSEMPMS PK_BSEMPMS) */ *FROM BSEMPMS WHERE DPT_NO='SCOTT';
9、/*+ INDEX_FFS(TABLE INDEX_NAME) */
对指定的表执行快速全索引扫描,而不是全表扫描的办法.
SELECT /* + INDEX_FFS(BSEMPMS IN_EMPNAM)*/ * FROM BSEMPMS WHERE DPT_NO='TEC305';

10、/*+ INDEX_SS(T T_IND) */
从9i开始,oracle引入了这种索引访问方式。当在一个联合索引中,某些谓词条件并不在联合索引的第一列时,可以通过Index Skip Scan来访问索引获得数据。当联合索引第一列的唯一值个数很少时,使用这种方式比全表扫描效率高。

SQL> create table t as select 1 id,object_name from dba_objects;
Table created.
SQL> insert into t select 2,object_name from dba_objects;      
50366 rows created.
SQL> insert into t select 3,object_name from dba_objects;      
50366 rows created.

SQL> insert into t select 4,object_name from dba_objects;      
50366 rows created.

SQL> commit;
Commit complete.
SQL> create index t_ind on t(id,object_name);
Index created.
SQL> exec dbms_stats.gather_table_stats('HR','T',cascade=>true);
PL/SQL procedure successfully completed.
执行全表扫描
SQL> select /*+ full(t) */ * from t where object_name='EMPLOYEES';
6 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     5 |   135 |   215   (3)| 00:00:03 |
|*  1 |  TABLE ACCESS FULL| T    |     5 |   135 |   215   (3)| 00:00:03 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("OBJECT_NAME"='EMPLOYEES')
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        942  consistent gets
          0  physical reads
          0  redo size
        538  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          6  rows processed
不采用hint
SQL>  select * from t where object_name='EMPLOYEES';
6 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2869677071
--------------------------------------------------------------------------
| Id  | Operation        | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT |       |     5 |   135 |     5   (0)| 00:00:01 |
|*  1 |  INDEX SKIP SCAN | T_IND |     5 |   135 |     5   (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("OBJECT_NAME"='EMPLOYEES')
       filter("OBJECT_NAME"='EMPLOYEES')
Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
         17  consistent gets
          1  physical reads
          0  redo size
        538  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          6  rows processed
当全表扫描扫描了942个块,联合索引只扫描了17个数据块。可以看到联合索引的第一个字段的值重复率很高时,即使谓词中没有联合索引的第一个字段,依然会使用index_ss方式,效率远远高于全表扫描效率。但当
第一个字段的值重复率很低时,使用index_ss的效率要低于全表扫描,读者可以自行实验
和表的关联相关的hint

/*+ leading(table_1,table_2) */

在多表关联查询中,指定哪个表作为驱动表,即告诉优化器首先要访问哪个表上的数据。
select /*+ leading(t,t1) */ t.* from t,t1 where t.id=t1.id;
/*+ order */

让Oracle根据from后面表的顺序来选择驱动表,oracle建议使用leading,他更为灵活
select /*+ order */ t.* from t,t1 where t.id=t1.id;
/*+ use_nl(table_1,table_2) */
在多表关联查询中,指定使用nest loops方式进行多表关联。

select /*+ use_nl(t,t1) */ t.* from t,t1 where t.id=t1.id;

/*+ use_hash(table_1,table_2) */
在多表关联查询中,指定使用hash join方式进行多表关联。

select /*+ use_hash(t,t1) */ t.* from t,t1 where t.id=t1.id;

在多表关联查询中,指定使用hash join方式进行多表关联,并指定表t为驱动表。

select /*+ use_hash(t,t1) leading(t,t1) */ t.* from t,t1 where t.id=t1.id;

/*+ use_merge(table_1,table_2) */
在多表关联查询中,指定使用merge join方式进行多表关联。

select /*+ use_merge(t,t1) */ t.* from t,t1 where t.id=t1.id;

/*+ no_use_nl(table_1,table_2) */
在多表关联查询中,指定不使用nest loops方式进行多表关联。

select /*+ no_use_nl(t,t1) */ t.* from t,t1 where t.id=t1.id;

/*+ no_use_hash(table_1,table_2) */
在多表关联查询中,指定不使用hash join方式进行多表关联。

select /*+ no_use_hash(t,t1) */ t.* from t,t1 where t.id=t1.id;

/*+ no_use_merge(table_1,table_2) */
在多表关联查询中,指定不使用merge join方式进行多表关联。

select /*+ no_use_merge(t,t1) */ t.* from t,t1 where t.id=t1.id;

其他常用的hint

/*+ parallel(table_name n) */

在sql中指定执行的并行度,这个值将会覆盖自身的并行度

select /*+ parallel(t 4) */ count(*)  from t;

/*+ no_parallel(table_name) */

在sql中指定执行的不使用并行

select /*+ no_parallel(t) */ count(*)  from t;

/*+ append */以直接加载的方式将数据加载入库

insert into t /*+ append */ select * from t;

/*+ dynamic_sampling(table_name n) */

设置sql执行时动态采用的级别,这个级别为0~10
select /*+ dynamic_sampling(t 4) */ * from t where id > 1234

/*+ cache(table_name) */
进行全表扫描时将table置于LRU列表的最活跃端,类似于table的cache属性

select /*+ full(employees) cache(employees) */ last_name from employees
附录hint表格

Hints for Optimization Approaches and Goals

ALL_ROWSThe ALL_ROWS hint explicitly chooses the cost-based approach tooptimize a statement block with a goal of best throughput(that is, minimum total resource consumption).FIRST_ROWSThe FIRST_ROWS hint explicitly chooses the cost-based approach to optimize a statement block with a goal of best response time (minimum resource usage to return first row).In newer Oracle version you should give a parameter with this hint: FIRST_ROWS(n) means that the optimizer willdetermine an executionplan to give a fast response for returning the first n rows.CHOOSEThe CHOOSE hint causes the optimizer to choose between the rule-based approach and the cost-based approach for a SQL statement based on the presence of statistics for the tables accessed by the statementRULEThe RULE hint explicitly chooses rule-based optimization for a statement block. This hint also causes the optimizer to ignore any other hints specified for the statement block.The RULE hint does not work any more in Oracle 10g.

Hints for Access Paths

FULLThe FULL hint explicitly chooses a full table scan for the specified table. The syntax of the FULL hint isFULL(table)where table specifies the alias of the table (or table name if alias does not exist) on which the full table scan is to be performed.ROWIDThe ROWID hint explicitly chooses a table scan by ROWID for the specified table. The syntax of the ROWID hint isROWID(table)where table specifies the name or alias of the table on which the table access by ROWID is to be performed. (This hint depricated in Oracle 10g)CLUSTERThe CLUSTER hint explicitly chooses a cluster scan to access the specified table. The syntax of the CLUSTER hint isCLUSTER(table)where table specifies the name or alias of the table to be accessed by a cluster scan.HASHThe HASH hint explicitly chooses a hash scan to access the specified table. The syntax of the HASH hint isHASH(table)where table specifies the name or alias of the table to be accessed by a hash scan.HASH_AJThe HASH_AJ hint transforms a NOT IN subquery into a hash anti-join to access the specified table. The syntax of the HASH_AJ hint isHASH_AJ(table)where table specifies the name or alias of the table to be accessed.(depricated in Oracle 10g)INDEXThe INDEX hint explicitly chooses an index scan for the specified table.The syntax of the INDEX hint is INDEX(table index)where:table specifies the name or alias of the table associated with the indexto be scanned and index specifies an index on which an index scan is to be performed.This hint may optionally specify one or more indexes:NO_INDEXThe NO_INDEX hint explicitly disallows a set of indexes for the specified table.The syntax of the NO_INDEX hint is NO_INDEX(table index)INDEX_ASCThe INDEX_ASC hint explicitly chooses an index scan for the specified table.If the statement uses an index range scan, Oracle scans the index entries in ascending order of their indexed values.INDEX_COMBINEIf no indexes are given as arguments for the INDEX_COMBINE hint, the optimizerwill use on the table whatever boolean combination of bitmap indexes has thebest cost estimate. If certain indexes are given as arguments, the optimizerwill try to use some boolean combination of those particular bitmap indexes.The syntax of INDEX_COMBINE is INDEX_COMBINE(table index).INDEX_JOIN Explicitly instructs the optimizer to use an index join as an access path. For the hint to have a positive effect, a sufficiently small number of indexes must exist that contain all the columns required to resolve the query.INDEX_DESCThe INDEX_DESC hint explicitly chooses an index scan for the specified table. If the statementuses an index range scan, Oracle scans the index entries in descending order oftheir indexed values.INDEX_FFSThis hint causes a fast full index scan to be performed rather than a full table.NO_INDEX_FFSDo not use fast full index scan (from Oracle 10g)INDEX_SSExclude range scan from query plan (from Oracle 10g)INDEX_SS_ASCExclude range scan from query plan (from Oracle 10g)INDEX_SS_DESC Exclude range scan from query plan (from Oracle 10g)NO_INDEX_SS The NO_INDEX_SS hint causes the optimizer to exclude a skip scan of the specified indexes on the specified table. (from Oracle 10g)

Hints for Query Transformations

NO_QUERY_TRANSFORMATION Prevents the optimizer performing query transformations. (from Oracle 10g)USE_CONCATThe USE_CONCAT hint forces combined OR conditions in the WHERE clause of aquery to be transformed into a compound query using the UNION ALLset operator. Normally, this transformation occurs only if the costof the query using the concatenations is cheaper than the cost without them.NO_EXPANDThe NO_EXPAND hint prevents the optimizer from considering OR-expansion for queries having OR conditions or IN-lists in the WHERE clause. Usually, the optimizer considers using OR expansion and uses this method if it decides that the cost is lower than not using it.REWRITEThe REWRITE hint forces the optimizer to rewrite a query in terms of materialized views, when possible, without cost consideration. Use the REWRITE hint with or without a view list. If you use REWRITE with a view list and the list contains an eligible materialized view, then Oracle uses that view regardless of its cost.NOREWRITE / NO_REWRITE In Oracle 10g renamed to NO_REWRITE.The NOREWRITE/NO_REWRITE hint disables query rewrite for the query block, overriding the setting of the parameter QUERY_REWRITE_ENABLED.MERGEThe MERGE hint lets you merge views in a query.NO_MERGEThe NO_MERGE hint causes Oracle not to merge mergeable views.This hint is most often used to reduce the number of possible permutations for a query and make optimization faster.FACTThe FACT hint indicated that the table should be considered as a fact table. This is used in the context of the star transformation.NO_FACTThe NO_FACT hint is used in the context of the star transformation to indicate to the transformation that the hinted table should not be considered as a fact table.STAR_TRANSFORMATIONThe STAR_TRANSFORMATION hint makes the optimizer use the best plan in which the transformation has been used. Without the hint, the optimizer could make a query optimization decision to use the best plan generated without the transformation, instead of the best plan for the transformed query.NO_STAR_TRANSFORMATION Do not use star transformation (from Oracle 10g)UNNESTThe UNNEST hint specifies subquery unnesting.NO_UNNESTUse of the NO_UNNEST hint turns off unnesting for specific subquery blocks.

Hints for Join Orders

LEADINGGive this hint to indicate the leading table in a join.This will indicate only 1 table. If you want to specify the whole order of tables, you can use the ORDERED hint.Syntax: LEADING(table)ORDEREDThe ORDERED hint causes Oracle to join tables in the order in whichthey appear in the FROM clause.If you omit the ORDERED hint from a SQL statement performing a join, the optimizer chooses the order in which to join the tables.You may want to use the ORDERED hint to specify a join order if you knowsomething about the number of rows selected from each table that theoptimizer does not. Such information would allow you to choose aninner and outer table better than the optimizer could.

Hints for Join Operations

USE_NLThe USE_NL hint causes Oracle to join each specified table to another rowsource with a nested loops join using the specified table as the inner table.The syntax of the USE_NL hint is USE_NL(table table)where table is the name or alias of a table to be used as the inner tableof a nested loops join.NO_USE_NLDo not use nested loop (from Oracle 10g)USE_NL_WITH_INDEX Specifies a nested loops join. (from Oracle 10g)USE_MERGEThe USE_MERGE hint causes Oracle to join each specified table with another rowsource with a sort-merge join. The syntax of the USE_MERGE hint isUSE_MERGE(table table) where table is a table to be joined to the row sourceresulting from joining the previous tables in the join order using asort-merge join.NO_USE_MERGEDo not use merge (from Oracle 10g)USE_HASHThe USE_HASH hint causes Oracle to join each specified table with anotherrow source with a hash join. The syntax of the USE_HASH hint isUSE_HASH(table table) where table is a table to be joined to the rowsource resulting from joining the previous tables in the join orderusing a hash join.NO_USE_HASHDo not use hash (from Oracle 10g)Hints for Parallel ExecutionPARALLELThe PARALLEL hint allows you to specify the desired number of concurrentquery servers that can be used for the query. The syntax isPARALLEL(table number number). The PARALLEL hint must use the table aliasif an alias is specified in the query. The PARALLEL hint can then taketwo values separated by commas after the table name.The first value specifies the degree of parallelism for the given table,the second value specifies how the table is to be split among the instances ofa parallel server. Specifying DEFAULT or no value signifies the querycoordinator should examine the settings of the initialization parameters(described in a later section) to determine the default degree of parallelism.NOPARALLEL / NO_PARALLELThe NOPARALLEL hint allows you to disable parallel scanning of a table, evenif the table was created with a PARALLEL clause. In Oracle 10g this hint was renamed to NO_PARALLEL.PQ_DISTRIBUTEThe PQ_DISTRIBUTE hint improves the performance of parallel join operations. Do this by specifying how rows of joined tables should be distributed among producer and consumer query servers. Using this hint overrides decisions the optimizer would normally make.NO_PARALLEL_INDEXThe NO_PARALLEL_INDEX hint overrides a PARALLEL attribute setting on an index to avoid a parallel index scan operation.Additional HintsAPPENDWhen the APPEND hint is used with the INSERT statement, data is appended to the table. Existing free space in the block is not used.If a table or an index is specified with nologging, this hint applied with an insert statement produces a direct path insert which reduces generation of redo. NOAPPENDOverrides the append mode. CACHEThe CACHE hint specifies that the blocks retrieved for the tablein the hint are placed at the most recently used end of the LRUlist in the buffer cache when a full table scan is performed.This option is useful for small lookup tables. In the followingexample, the CACHE hint overrides the table default caching specification.NOCACHEThe NOCACHE hint specifies that the blocks retrieved for this tableare placed at the least recently used end of the LRU list in the buffercache when a full table scan is performed. This is the normal behaviorof blocks in the buffer cache.PUSH_PREDThe PUSH_PRED hint forces pushing of a join predicate into the view.NO_PUSH_PREDThe NO_PUSH_PRED hint prevents pushing of a join predicate into the view.PUSH_SUBQThe PUSH_SUBQ hint causes nonmerged subqueries to be evaluated at the earliest possibleplace in the execution plan.NO_PUSH_SUBQThe NO_PUSH_SUBQ hint causes non-merged subqueries to be evaluated as the last step in the execution plan.QB_NAME Specifies a name for a query block. (from Oracle 10g)CURSOR_SHARING_EXACTOracle can replace literals in SQL statements with bind variables, if it is safe to do so. This is controlled with the CURSOR_SHARING startup parameter. The CURSOR_SHARING_EXACT hint causes this behavior to be switched off. In other words, Oracle executes the SQL statement without any attempt to replace literals by bind variables.DRIVING_SITEThe DRIVING_SITE hint forces query execution to be done for the table at a different site than that selected by OracleDYNAMIC_SAMPLINGThe DYNAMIC_SAMPLING hint lets you control dynamic sampling to improve server performance by determining more accurate predicate selectivity and statistics for tables and indexes. You can set the value of DYNAMIC_SAMPLING to a value from 0 to 10. The higher the level, the more effort the compiler puts into dynamic sampling and the more broadly it is applied. Sampling defaults to cursor level unless you specify a table.SPREAD_MIN_ANALYSISThis hint omits some of the compile time optimizations of the rules, mainly detailed dependency graph analysis, on spreadsheets. Some optimizations such as creating filters to selectively populate spreadsheet access structures and limited rule pruning are still used.(from Oracle 10g)

Hints with unknown status

MERGE_AJThe MERGE_AJ hint transforms a NOT IN subquery into a merge anti-join to access the specified table. The syntax of the MERGE_AJ hint isMERGE_AJ(table) where table specifies the name or alias of the table to be accessed.(depricated in Oracle 10g)AND_EQUALThe AND_EQUAL hint explicitly chooses an execution plan that uses an accesspath that merges the scans on several single-column indexes.The syntax of the AND_EQUAL hint is AND_EQUAL(table index index)where table specifies the name or alias of the table associated with the indexes to be merged.and index specifies an index on which an index scan is to be performed.You must specify at least two indexes. You cannot specify more than five.(depricated in Oracle 10g)STARThe STAR hint forces the large table to be joined last using a nested loopsjoin on the index. The optimizer will consider different permutations ofthe small tables. (depricated in Oracle 10g)BITMAPUsage: BITMAP(table_name index_name)Uses a bitmap index to access the table. (depricated ?)HASH_SJ
Use a Hash Anti-Join to evaluate a NOT IN sub-query. Use this hint in the sub-query, not in the main query.Use this when your high volume NOT IN sub-query is using a FILTER or NESTED LOOPS join. Try MERGE_AJ if HASH_AJ refuses to work.(depricated in Oracle 10g)NL_SJUse a Nested Loop in a sub-query. (depricated in Oracle 10g)NL_AJUse an anti-join in a sub-query. (depricated in Oracle 10g)ORDERED_PREDICATES (depricated in Oracle 10g)
EXPAND_GSET_TO_UNION (depricated in Oracle 10g)


参考至:《让Oracle跑得更快》谭怀远著

              http://www.oradev.com/hints.jsp

              http://hi.baidu.com/lyq168/blog/item/c813452c29d307e48a1399b1.html

              http://database.51cto.com/art/200911/163085.htm

              http://oracle.chinaitlab.com/induction/398193.html
本文原创,转载请注明出处
如有错误,欢迎指正
邮箱:czmcj@163.com


==================================


ORACLE的HINT详解
2013-05-17 08:58:55     我来说两句       作者:cqh520llr
收藏  我要投稿
ORACLE的HINT详解
 
  hints是oracle提供的一种机制,用来告诉优化器按照我们的告诉它的方式生成执行计划。我们可以用hints来实现:  
  
  1) 使用的优化器的类型  
  
  2) 基于代价的优化器的优化目标,是all_rows还是first_rows。  
  
  3) 表的访问路径,是全表扫描,还是索引扫描,还是直接利用rowid。  
  
  4) 表之间的连接类型  
  
  5) 表之间的连接顺序  
  
  6) 语句的并行程度  
  
  2、HINT可以基于以下规则产生作用  
  
  表连接的顺序、表连接的方法、访问路径、并行度  
  
  3、HINT应用范围  
  
  dml语句  
  
  查询语句  
  
  4、语法  
  
  {DELETE|INSERT|SELECT|UPDATE} /*+ hint [text] [hint[text]]... */  
  
  or  
  
  {DELETE|INSERT|SELECT|UPDATE} --+ hint [text] [hint[text]]...  
  
  如果语(句)法不对,则ORACLE会自动忽略所写的HINT,不报错  
  
  1. /*+ALL_ROWS*/  
  
  表明对语句块选择基于开销的优化方法,并获得最佳吞吐量,使资源消耗最小化.  
  
  例如:  
  
  SELECT /*+ALL_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';  
  
  2. /*+FIRST_ROWS*/  
  
  表明对语句块选择基于开销的优化方法,并获得最佳响应时间,使资源消耗最小化.  
  
  例如:  
  
  SELECT /*+FIRST_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';  
  
  3. /*+CHOOSE*/  
  
  表明如果数据字典中有访问表的统计信息,将基于开销的优化方法,并获得最佳的吞吐量;  
  
  表明如果数据字典中没有访问表的统计信息,将基于规则开销的优化方法;  
  
  例如:  
  
  SELECT /*+CHOOSE*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';  
  
  4. /*+RULE*/  
  
  表明对语句块选择基于规则的优化方法.  
  
  例如:  
  
  SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';  
  
  5. /*+FULL(TABLE)*/  
  
  表明对表选择全局扫描的方法.  
  
  例如:  
  
  SELECT /*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO='SCOTT';  
  
  6. /*+ROWID(TABLE)*/  
  
  提示明确表明对指定表根据ROWID进行访问.  
  
  例如:  
  
  SELECT /*+ROWID(BSEMPMS)*/ * FROM BSEMPMS WHERE ROWID>='AAAAAAAAAAAAAA'  
  
  AND EMP_NO='SCOTT';  
  
  7. /*+CLUSTER(TABLE)*/  
  
  提示明确表明对指定表选择簇扫描的访问方法,它只对簇对象有效.  
  
  例如:  
  
  SELECT /*+CLUSTER */ BSEMPMS.EMP_NO,DPT_NO FROM BSEMPMS,BSDPTMS  
  
  WHERE DPT_NO='TEC304' AND BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;  
  
  8. /*+INDEX(TABLE INDEX_NAME)*/  
  
  表明对表选择索引的扫描方法.  
  
  例如:  
  
  SELECT /*+INDEX(BSEMPMS SEX_INDEX) USE SEX_INDEX BECAUSE THERE ARE FEWMALE BSEMPMS */ FROM BSEMPMS WHERE SEX='M';  
  
  9. /*+INDEX_ASC(TABLE INDEX_NAME)*/  
  
  表明对表选择索引升序的扫描方法.  
  
  例如:  
  
  SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='SCOTT';  
  
  10. /*+INDEX_COMBINE*/  
  
  为指定表选择位图访问路经,如果INDEX_COMBINE中没有提供作为参数的索引,将选择出位图索引的布尔组合方式.  
  
  例如:  
  
  SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI)*/ * FROM BSEMPMS  
  
  WHERE SAL<5000000 AND HIREDATE  
  
  11. /*+INDEX_JOIN(TABLE INDEX_NAME)*/  
  
  提示明确命令优化器使用索引作为访问路径.  
  
  例如:  
  
  SELECT /*+INDEX_JOIN(BSEMPMS SAL_HMI HIREDATE_BMI)*/ SAL,HIREDATE  
  
  FROM BSEMPMS WHERE SAL<60000;  
  
  12. /*+INDEX_DESC(TABLE INDEX_NAME)*/  
  
  表明对表选择索引降序的扫描方法.  
  
  例如:  
  
  SELECT /*+INDEX_DESC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='SCOTT';  
  
  13. /*+INDEX_FFS(TABLE INDEX_NAME)*/  
  
  对指定的表执行快速全索引扫描,而不是全表扫描的办法.  
  
  例如:  
  
  SELECT /*+INDEX_FFS(BSEMPMS IN_EMPNAM)*/ * FROM BSEMPMS WHERE DPT_NO='TEC305';  
  
  14. /*+ADD_EQUAL TABLE INDEX_NAM1,INDEX_NAM2,...*/  
  
  提示明确进行执行规划的选择,将几个单列索引的扫描合起来.  
  
  例如:  
  
  SELECT /*+INDEX_FFS(BSEMPMS IN_DPTNO,IN_EMPNO,IN_SEX)*/ * FROM BSEMPMS WHERE EMP_NO='SCOTT' AND DPT_NO='TDC306';  
  
  15. /*+USE_CONCAT*/  
  
  对查询中的WHERE后面的OR条件进行转换为UNION ALL的组合查询.  
  
  例如:  
  
  SELECT /*+USE_CONCAT*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';  
  
  16. /*+NO_EXPAND*/  
  
  对于WHERE后面的OR 或者IN-LIST的查询语句,NO_EXPAND将阻止其基于优化器对其进行扩展.  
  
  例如:  
  
  SELECT /*+NO_EXPAND*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';  
  
  17. /*+NOWRITE*/  
  
  禁止对查询块的查询重写操作.  
  
  18. /*+REWRITE*/  
  
  可以将视图作为参数.  
  
  19. /*+MERGE(TABLE)*/  
  
  能够对视图的各个查询进行相应的合并.  
  
  例如:  
  
  SELECT /*+MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELET DPT_NO  
  
  ,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO  
  
  AND A.SAL>V.AVG_SAL;  
  
  20. /*+NO_MERGE(TABLE)*/  
  
  对于有可合并的视图不再合并.  
  
  例如:  
  
  SELECT /*+NO_MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELECT DPT_NO,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO AND A.SAL>V.AVG_SAL;  
  
  21. /*+ORDERED*/  
  
  根据表出现在FROM中的顺序,ORDERED使ORACLE依此顺序对其连接.  
  
  例如:  
  
  SELECT /*+ORDERED*/ A.COL1,B.COL2,C.COL3 FROM TABLE1 A,TABLE2 B,TABLE3 C WHERE A.COL1=B.COL1 AND B.COL1=C.COL1;  
  
  22. /*+USE_NL(TABLE)*/  
  
  将指定表与嵌套的连接的行源进行连接,并把指定表作为内部表.  
  
  例如:  
  
  SELECT /*+ORDERED USE_NL(BSEMPMS)*/ BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;  
  
  23. /*+USE_MERGE(TABLE)*/  
  
  将指定的表与其他行源通过合并排序连接方式连接起来.  
  
  例如:  
  
  SELECT /*+USE_MERGE(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;  
  
  24. /*+USE_HASH(TABLE)*/  
  
  将指定的表与其他行源通过哈希连接方式连接起来.  
  
  例如:  
  
  SELECT /*+USE_HASH(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;  
  
  25. /*+DRIVING_SITE(TABLE)*/  
  
  强制与ORACLE所选择的位置不同的表进行查询执行.  
  
  例如:  
  
  SELECT /*+DRIVING_SITE(DEPT)*/ * FROM BSEMPMS,DEPT@BSDPTMS WHERE BSEMPMS.DPT_NO=DEPT.DPT_NO;  
  
  26. /*+LEADING(TABLE)*/  
  
  将指定的表作为连接次序中的首表.  
  
  27. /*+CACHE(TABLE)*/  
  
  当进行全表扫描时,CACHE提示能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使用端  
  
  例如:  
  
  SELECT /*+FULL(BSEMPMS) CAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;  
  
  28. /*+NOCACHE(TABLE)*/  
  
  当进行全表扫描时,CACHE提示能够将表的检索块放置在缓冲区缓存中最近最少列表LRU的最近使用端  
  
  例如:  
  
  SELECT /*+FULL(BSEMPMS) NOCAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;  
  
  29. /*+APPEND*/  
  
  直接插入到表的最后,可以提高速度.  
  
  insert /*+append*/ into test1 select * from test4 ;  
  
  30. /*+NOAPPEND*/  
  
  通过在插入语句生存期内停止并行模式来启动常规插入.  
  
  insert /*+noappend*/ into test1 select * from test4 ;  
  
  31. NO_INDEX: 指定不使用哪些索引  
  
  /*+ NO_INDEX ( table [index [index]...] ) */  
  
  select /*+ no_index(emp ind_emp_sal ind_emp_deptno)*/ * from emp where deptno=200 and sal>300;  
  
  32. parallel  
  
  select /*+ parallel(emp,4)*/ * from emp where deptno=200 and sal>300;  
  
  另:每个SELECT/INSERT/UPDATE/DELETE命令后只能有一个/*+ */,但提示内容可以有多个,可以用逗号分开,空格也可以。  
  
  如:/*+ ordered index() use_nl() */  
  
---------  
类似如下的一条语句:insert into xxxx select /*+parallel(a) */ * from xxx a;数据量大约在75G左右,这位兄弟从上午跑到下午还没跑完,过来问我咋回事,说平常2hrs能跑完的东西跑了好几个小时还撒动静。查看系统性能也比较 正常,cpu,io都不繁忙,平均READ速度在80M/s左右(勉强凑合),但平均写速度只有10M不到。等待事件里面大量的‘ ‘PX Deq Credit: send blkd’,这里能看出并行出了问题,从而最后得知是并行用法有问题,修改之后20分钟完成了该操作。正确的做法应该是:  
alter session enable dml parallel;  
  
insert /*+parallel(xxxx,4) */ into xxxx select /*+parallel(a) */ * from xxx a;  
  
因为oracle默认并不会打开PDML,对DML语句必须手工启用。 另外不得不说的是,并行不是一个可扩展的特性,只有在数据仓库或作为DBA等少数人的工具在批量数据操作时利于充分利用资源,而在OLTP环境下使用并行 需要非常谨慎。事实上PDML还是有比较多的限制的,例如不支持触发器,引用约束,高级复制和分布式事务等特性,同时也会带来额外的空间占用,PDDL同 样是如此。
---------  
select count(*)  
  From wid_serv_prod_mon_1100 a  
 where a.acct_month = 201010  
   and a.partition_id = 10  
   and serv_state not in ('2HB', '2HL', '2HJ', '2HP', '2HF')  
   and online_flag in (0)  
   and incr_product_id in (2000020)  
   and product_id in (2020966, 2020972, 2100297, 2021116)  
   and billing_mode_id = 1  
   and exp_date > to_date('201010', 'yyyymm')  
   and not exists (select /*+no_index (b IDX_W_CDR_MON_SERV_ID_1100)*/  
         1  
          from wid_cdr_mon_1100 b  
         where b.acct_month = 201010  
           and b.ANA_EVENT_TYPE_4 in  
               ('10201010201', '10202010201', '10203010201', '10203010202', '10203030201', '10203030202', '10204010201', '10204010202', '10204030201')  
           and a.serv_id = b.serv_id) 
参考:


oracle hit   百度

物化视图 hit    谷歌

强制 物化视图 hit

0 0
原创粉丝点击