ORACLE SQL HINTS
Optimizer - SQL Hints
Sometimes, the optimizer needs some suggestions in order to make the best possible choice, even when armed with good statistics. These suggestions can be given to the optimizer in the form of hints in your SQL statements. While hints give direction to the optimizer, the optimizer is under no obligation to follow them every time.
Hints are specified by enclosing the hint in a comment in the query. Multiple hints can be contained in the comment. The comment must follow the SELECT, INSERT, UPDATE, or DELETE keyword and must contain a plus sign, '+' at the start. If the hint is not specified properly, then it will be ignored with no errors or warnings from the optimizer. A hint is specified as follows:
SELECT /*+ hint [text] [hint [text]] … */ ….
Or
/*+ hint */
/*+ hint(argument) */
/*+ hint(argument-1 argument-2) */
An example of a hint is as follows:
SELECT /*+ INDEX( e emp_pk) */
FROM emp e
WHERE empid IN (1001, 1002);
In the above example, the INDEX hint is used to suggest a specific index to the optimizer. Normally, a table name is denoted to define which table to use that index, but in this example the table was aliased in the FROM clause, therefore the hint must use the table's alias. If the table was aliased in the FROM clause, and the table name was used in the hint, the hint would be ignored.
All hints except /*+ rule */ cause the CBO to be used. Therefore, it is good practice to analyze the underlying tables if hints are used (or the query is fully hinted.
There should be no schema names in hints. Hints must use aliases if alias names are used for table names. So the following is wrong:
select /*+ index(scott.emp ix_emp) */ from scott.emp emp_alias
better:
select /*+ index(emp_alias ix_emp) */ ... from scott.emp emp_alias
Why to Use Hints
It is a perfect valid question to ask why hints should be used. Oracle comes with an optimizer that promises to optimize aquery's execution plan. When this optimizer is really doing a good job, no hints should be required at all.
Sometimes, however, the characteristics of the data in the database are changing rapidly, so that the optimizer (or more accuratly, its statistics) are out of date. In this case, a hint could help.
It must also be noted, that Oracle allows to lock the statistics when they look ideal which should make the hints meaningless again.
Hint categories
Hints can be categorized as follows:
- Hints for Optimization Approaches and Goals,
- Hints for Access Paths, Hints for Query Transformations,
- Hints for Join Orders,
- Hints for Join Operations,
- Hints for Parallel Execution,
- Miscellaneous Hints
1. Optimizer Mode Hints
The optimizer mode for the SQL statement can be specified as a hint. This overrides the instance and session settings for the optimizer mode. The optimizer hints are as follows:
ALL_ROWS
- return all rows as fast as possible
- One of the hints that 'invokes' the Cost based optimizer
- ALL_ROWS is usually used for batch processing or data warehousing systems.
FIRST_ROWS(n)
- return the first n rows as fast as possible, where n is 1, 10, 100, or 1000.
- One of the hints that 'invokes' the Cost based optimizer
- FIRST_ROWS is usually used for OLTP systems.
RULE
- use to denote Rule Based Optimization. Not valid in Oracle 10g.
- The RULE hint should be considered deprecated as it is dropped from Oracle9i2.
CHOOSE
- use to denote Cost Based Optimization. Not valid in Oracle 10g.
- One of the hints that 'invokes' the Cost based optimizer
- This hint lets the server choose (between ALL_ROWS and FIRST_ROWS, based on statistics gathered
2. Access Path Hints
There are many ways to access data in a table. You can perform a full table scan or access the data using an index on the table. If using an index, you can use it in ascending mode or descending mode. The access path hints are:
CLUSTER
- Performs a nested loop by the cluster index of one of the tables.
HASH
- Hashes one table (full scan) and creates a hash index for that table. Then hashes other table and uses hash index to find corresponding records. Therefore not suitable for < or > join conditions.
ROWID
- Retrieves the row by rowid
INDEX
- Specifying that index index_name should be used on table tab_name: /*+ index (tab_name index_name) */
- Specifying that the index should be used the the CBOthinks is most suitable. (Not always a good choice).
- Starting with Oracle 10g, the index hint can be described: /*+ index(my_tab my_tab(col_1, col_2)) */. Using the index on my_tab that starts with the columns col_1 and col_2.
INDEX_COMBINE
AND_EQUAL
The AND_EQUAL hint explicitly chooses an execution plan that uses an access path that merges the scans on several single-column indexes
FULL suggests a full table scan
NO_INDEX suggests not to use an index
INDEX_ASC suggests to use an index in ascending mode
INDEX_DESC suggests to use an index in descending mode
INDEX_JOIN suggests to use an index join access method
INDEX_FFS suggests to use an index full fast scan
NO_INDEX_FFS suggests not to use an index full fast scan
INDEX_SS suggests to use an index skip scan. Available only in Oracle 10g.
INDEX_SS_ASC suggests to use an index skip scan in ascending mode. Available only in Oracle 10g.
INDEX_SS_DESC suggests to use an index skip scan in descending mode. Available only in Oracle 10g.
NO_INDEX_SS suggests not to use an index skip scan. Available only in Oracle 10g.
3. Join Hints
There are many methods used to join two tables together. The join hints are:
- USE_NL Use a Nested Loop join method. Can specify the inner table.
- NO_USE_NL Do not use a Nested Loop join method. Available only in Oracle 10g.
- USE_NL_WITH_INDEX Use a Nested Loop join method with an index. Available only in Oracle 10g.
- USE_MERGE Use a Sort Merge join method. Can specify the inner table.
- NO_USE_MERGE Do not use a Sort Merge join method. Available only in Oracle 10g.
- USE_HASH Use a Hash join method. Can specify the inner table
- NO_USE_HASH Do not use the Hash join method. Available only in Oracle 10g.
4. Parallel Hints
There are a number of hints used in parallel processing of queries. Parallel queries use multiple processors on the database server to obtain results faster. The paralle hints are:
- PARALLEL(n) Suggest to perform the operation in parallel. The degree of parallelization, n, can be specified.
- NO_PARALLEL Suggest to not perform the query in parallel. This overrides the parallel specification for a table.
- PARALLEL_INDEX(n) Suggest to parallelize the index range scan. The degree of parallelization, n, can be specified.
- NO_PARALLEL_INDEX Suggest to not parallelize the index range scan.
5. Miscellaneous Hints
The miscellaneous hints are:
- APPEND
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
- NOAPPEND Disables Direct Path insert mode.
- CACHE Blocks accessed with this query are placed on the most recently used end of the LRU list.
- NOCACHE Blocks accessed with this query are placed on the least recently used end of the LRU list.
- PUSH_SUBQ Causes subqueries to be evaluated at the earliest possible time.
- NO_PUSH_SUBQ Causes subqueries to be evaluated at the last possible time.
- DRIVING_SITE Causes another database in a distributed query to be the driving site for the query.
- ANTIJOIN
- APPEND.
- BITMAP
- BUFFER
- CARDINALITY
- CPU_COSTING
- DYNAMIC_SAMPLING
- INLINE
- MATERIALIZE
- NO_ACCESS
- NO_BUFFER
- NO_MONITORING
- NO_PUSH_PRED
- NO_QKN_BUFF
- NO_SEMIJOIN
- OR_EXPAND
- ORDERED
- ORDERED_PREDICATES
- PUSH_PRED
- QB_NAME
- RESULT_CACHE (Oracle 11g)
- SELECTIVITY
- SEMIJOIN
- SEMIJOIN_DRIVER
- STAR
- The STAR hint forces a star query plan to be used, if possible. A star plan has the largest table in the query last in the join order and joins it with a nested loops join on a concatenated index. The STAR hint applies when there are at least three tables, the large table's concatenated index has at least three columns, and there are no conflicting access or join method hints. The optimizer also considers different permutations of the small tables.
- SWAP_JOIN_INPUTS
- USE_ANTI
- USE_SEMI
- BYPASS_RECURSIVE_CHECK
- Workaraound for bug 1816154
- BYPASS_UJVC
- CACHE_CB
- CACHE_TEMP_TABLE
- CIV_GB
- COLLECTIONS_GET_REFS
- CUBE_GB
- CURSOR_SHARING_EXACT
- DEREF_NO_REWRITE
- DML_UPDATE
- DOMAIN_INDEX_NO_SORT
- DOMAIN_INDEX_SORT
- DYNAMIC_SAMPLING
- DYNAMIC_SAMPLING_EST_CDN
- EXPAND_GSET_TO_UNION
- FORCE_SAMPLE_BLOCK
- GBY_CONC_ROLLUP
- GLOBAL_TABLE_HINTS
- HWM_BROKERED
- IGNORE_ON_CLAUSE
- IGNORE_WHERE_CLAUSE
- INDEX_RRS
- INDEX_SS
- INDEX_SS_ASC
- INDEX_SS_DESC
- LIKE_EXPAND
- LOCAL_INDEXES
- MV_MERGE
- NESTED_TABLE_GET_REFS
- NESTED_TABLE_SET_REFS
- NESTED_TABLE_SET_SETID
- NO_FILTERING
- NO_ORDER_ROLLUPS
- NO_PRUNE_GSETS
- NO_STATS_GSETS
- NO_UNNEST
- NOCPU_COSTING
- OVERFLOW_NOMOVE
- PIV_GB
- PIV_SSF
- PQ_MAP
- PQ_NOMAP
- REMOTE_MAPPED
- RESTORE_AS_INTERVALS
- SAVE_AS_INTERVALS
- SCN_ASCENDING
- SKIP_EXT_OPTIMIZER
- SQLLDR
- SYS_DL_CURSOR
- SYS_PARALLEL_TXN
- SYS_RID_ORDER
- TIV_GB
- TIV_SSF
- UNNEST
- USE_TTT_FOR_GSETS
No comments:
Post a Comment