Académique Documents
Professionnel Documents
Culture Documents
Introduction
Ask a diverse sample of Oracle professionals for their opinion concerning query hints, and their responses will tend to fall into one of three groupings: 1) What are hints all about, anyway? 2) Hints are one of the coolest features in Oracle, and they have rescued my career. 3) Hints are evil, and cause far more problems than they solve. Never, never use hints! In reality, hints can be detrimental to the performance and scalability of a database. Also, hints can be useful for achieving an optimally performing database. The key to success is understanding when, where, why and how hints should be used.
What is a hint?
A hint is a special syntax of a comment in a SQL statement block that specifies an instruction, or hint, to Oracles cost-based optimizer (CBO). The optimizer uses hints to influence or constrain its choice of an execution plan. Hints may appear in SQL originating from SQL*Plus, PL/SQL, Java, Toad, ODBC, C++, Cobol or any application with an Oracle SQL interface. Hints are specified within a statement block using either style of comment that Oracle supports: {DELETE|INSERT|SELECT|UPDATE} /*+ hint [text] [hint[text]]... */ or {DELETE|INSERT|SELECT|UPDATE} --+ hint [text] [hint[text]]... where: DELETE, INSERT, SELECT, or UPDATE is a query keyword that begins a statement block. Comments containing hints must appear immediately following these keywords. + is a plus sign that causes Oracle to interpret the comment as a list of hints. The plus sign must follow immediately after the comment delimiter (no space is permitted). hint is a validly constructed hint. The space between the plus sign and the hint is optional, and is recommended in PL/SQL prior to Oracle9i. If the comment contains multiple hints, then separate the hints by at least one space. text is other commenting text that can be interspersed with the hints.
Ordinarily the optimizer will choose a query plan designed to provide the best overall throughput and efficiency. However, quickest response might be a more important goal than overall throughput for an application such as a scrollable browser. You can bias the optimizer to do this with a more index-intensive plan by specifying the FIRST_ROWS hint. For example: SELECT /*+FIRST_ROWS*/ item_class, item_no, uom, description, qty FROM item_table JOIN item_availability
USING (item_no) WHERE item_class = :INPUT_CLASS AND qty > 0; The hints that influence optimization goals and approaches are: ALL_ROWS, FIRST_ROWS(n), CHOOSE and RULE.
Access Methods
You can recommend the use of a specific index, an index processing method, or even a full table scan, as a method for accessing a particular table that you specify. Influencing access methods is quite possibly the most prevalent use of hints, and it is replete with pitfalls. Note the use of an indexing hint in the subquery: SELECT domain_name, domain_owner FROM spammers m WHERE effdt = (SELECT /*+INDEX_DESC(s uce_effdt) */ MAX(effdt) -- retrieve only the latest FROM spammers s WHERE s.domain_name = m.domain_name); Here are the hints that influence a choice of access path: AND_EQUAL (table_alias index1 index2 ) CLUSTER (table_alias) FULL (table_alias) HASH (table_alias) NO_INDEX (table_alias [index_1 index2 ]) ROWID (table_alias) [index_name])
Join Order
INDEX (table_alias [index_name]) INDEX_ASC (table_alias [index_name]) INDEX_COMBINE (table_alias index1 index2 ) INDEX_DESC (table_alias [index_name]) INDEX_FFS (table_alias [index_name]) INDEX_JOIN (table_alias [index_name]) INDEX_SS (table_alias
The join order of tables in a FROM clause are affected with three hints, LEADING (table_alias), ORDERED and STAR. The STAR join method is useful only with a join of 3 or more tables, where the largest table has a concatenated index of at least 3 columns and there are no conflicting access or join method hints. The largest table is joined last in the join order, using a nested loops join to its qualifying concatenated index. The ORDERED hint will instruct the optimizer to join the tables in the order that they are specified, left to right, in the FROM clause. To be beneficial, use of this hint presumes that the query author has arranged the tables in the FROM clause according to immutable size and/or selectivity criteria, and that she understands some idiosyncrasy of the data distribution that the optimizer does not. This example query is constructed with the ORDERED hint: SELECT /*+ ORDERED */ e.last_name, e.first_name, b.branch_name FROM employee e JOIN branch b ON (branch_id) WHERE e.position = BRANCH MANAGER; The LEADING hint specifies which table is first in the join order, leaving the remainder of the ordering up to the CBO.
Join Operations
The choice of a join method is highly leveraged and can change the elapsed runtime of a query by a factor of up to several thousand times, favorably or unfavorably. Following is a synopsis of the hints that influence join operations. USE_HASH (table_1 [table_2 ]) HASH_AJ USE_MERGE (table_1 [table_2 ]) MERGE_AJ HASH_SJ MERGE_SJ
NL_AJ
NL_SJ
The anti-join hints HASH_AJ, MERGE_AJ and NL_AJ apply only to NOT IN or NOT EXISTS subquery blocks. The semi-join hints HASH_SJ, MERGE_SJ and NL_SJ are meaningful only when specified within EXISTS subquery blocks. Examples: SELECT /*+ DRIVING_SITE(wh1) */ wh1.* FROM my_list ml, big_warehouse_table@dwh wh1, lookup_table@dwh wh2 WHERE ml.market = wh1.market AND wh1.type = wh2.type AND wh2.status = ACTIVE; SELECT /*+ USE_HASH(E D) d.deptid, e.emplid */ FROM empl e JOIN dept d USING (e.empl_dept = d.deptid) WHERE d.dept_location = DENVER; SELECT division_name FROM division WHERE exists (SELECT /*+HASH_SJ*/ NULL FROM employee WHERE employee.division_id = division.division_id AND bonus > 25000);
Query Transformations
The query transformation category of hints has the effect of recasting the query as if it were written entirely differently for the same result. For example, observe the employment of a USE_CONCAT hint in this query: SELECT /*+ USE_CONCAT */ * FROM pub78 WHERE (state = 'CO' OR state = 'WY') AND UPPER(name) LIKE '%CATHOLIC%' The USE_CONCAT hint transforms the query (as confirmed with an EXPLAIN PLAN) as if it had been written: SELECT * FROM pub78 WHERE state = CO AND UPPER(name) LIKE '%CATHOLIC%' UNION ALL SELECT * FROM pub78 WHERE state = WY AND UPPER(name) LIKE '%CATHOLIC%' This is a list of the query transformation hints available: EXPAND_GSET_TO_UNION FACT (table_alias) MERGE (view_alias) REWRITE [(view1 [view2 ])] STAR_TRANSFORMATION
Parallel Execution
PARALLEL (table_alias, [degrees | DEFAULT][,{instances | DEFAULT}]) NOPARALLEL (table_alias) PQ_DISTRIBUTE (table_alias[,] outer_distribution, inner_distribution) PARALLEL_INDEX (table_alias, [degrees | DEFAULT][,{instances | DEFAULT}]) NOPARALLEL_INDEX (table_alias) This example is typical of the use of parallel query hints: INSERT /*+ APPEND PARALLEL(T_CPY,4) */ INTO t_cpy SELECT /*+ PARALLEL(T,2)*/ * FROM t;
Additional Operations
The final group of hints falls outside of the preceding categories. Here is a roster of documented additional hints: APPEND CACHE (table_alias) PUSH_PRED (view_alias) PUSH_SUBQ UNNEST NO_APPEND CURSOR_SHARING_EXACT NO_CACHE (table_alias) DYNAMIC_SAMPLING ([table_alias] level) NO_PUSH_PRED (view_alias) ORDERED_PREDICATES NO_PUSH_SUBQ NO_UNNEST
Included in this list are two hints that arguably can be incorporated into production SQL with little downside risk. The APPEND hint is used only in INSERT statements. Its inclusion instructs Oracle to bypass free space processing, and instead, to append new blocks to the table. This results in much quicker insert processing, at the possible cost of additional space usage. However, if the table is newly created, newly truncated, or if it has had few or no DELETE operations, there might not be a significant space trade-off at all. Index insertion is deferred when the APPEND hint is used. This is the direct-path insert method that can be optionally invoked with the SQL*Loader utility. Parallel INSERT implies APPEND. The DYNAMIC_SAMPLING hint is used to obtain cardinality and selectivity estimates on the fly. This can be a useful hint when performing queries on a global temporary table (GTT), for example, or where there is reason to believe that the table/index statistics might be inaccurate for use by the CBO. Notice that there is a required integer that specifies the level of sampling to be performed. Finally, there are a sizable number of undocumented hints. Ordinarily, these are used by Oracle internally, such as hints used for parallel query process coordination, and by Oracle support to identify or to work around particular CBO issues. Reliance on undocumented hints, even in development environments, is not recommended.
A Few Preliminaries
Ensure that the database environment is using the cost-based optimizer (CBO). This is set with the database initialization parameter, OPTIMIZER_MODE, which ordinarily should be set to ALL_ROWS or to CHOOSE. Also, be sure that the COMPATIBLE and OPTIMIZER_FEATURES_ENABLE parameters are set to versions that support the hints you use. Confirm that the participating tables and their indexes in the query have statistics, and that the statistics are reasonably current. Be sure to confirm this for tables within views and subqueries. Check that necessary initialization parameters are set. For example, for the PARALLEL hint to work at all, you must have Oracle Enterprise Edition, and parallel query servers must be configured using Oracle database initialization parameters.
Explanation: Hints generally apply only within the scope of the query block where they appear. Hints for a subquery must be included in the subquery itself. Hints to be applied to table(s) in a named or in-line view can be supplied in the view query; however, it is better practice to provide a global hint in the top-level query block, as shown above.
Global Hints
The execution plan of a view can be hinted from a particular query that references it, directly or indirectly, by using the global hint syntax. First, consider the following two related view definitions: CREATE VIEW manager AS SELECT * FROM employee e WHERE emp_role in (M,S,F); CREATE VIEW officer AS SELECT * FROM manager m WHERE is_officer = Y; Now, here is an example of how a global hint might be applied for use of a bitmap index on the EMPLOYEE table: SELECT /*+ INDEX(officer.m.e ix_emp_codes) */ dept_name, last_name, first_name FROM officer JOIN dept USING (dept_id); Note that the actual view name, OFFICER, was supplied in the hint because it has no alias in the query, while aliases were specified as they must be for the view MANAGER and the table EMPLOYEE. Global hints come in handy when you are working to optimize a query that references views delivered with an ERP or other application system. Global hints enable you to evaluate several plan scenarios without altering the third-party view at all.
If the hint provides improved results, you are not done! Now the root cause must be determined. Often, it will be because statistics on the index or table are missing or stale. Gather fresh statistics on all tables (and their indexes) that participate in the query, and see if that has an impact on the execution plan. If it does not, consider analyzing a 10053 trace on the query.
When traced, and then run through the Trace Analyzer, this output is presented: | Rows Row Source Operation | ------------ --------------------------------------------------| 12645 HASH JOIN (cr=8990 pr=382 pw=382 time=14.48) | 12880 .VIEW (cr=4432 pr=382 pw=382 time=7.86) | 12880 ..FILTER (cr=4432 pr=382 pw=382 time=7.79) | 34061 ...SORT GROUP BY (cr=4432 pr=382 pw=382 time=7.68) | 614578 ....TABLE ACCESS FULL OBJ# PUB78 (cr=4432 pr=0 pw=0 time=1.95) | 614578 .TABLE ACCESS FULL OBJ# PUB78 (cr=4558 pr=0 pw=0 time=1.89) Explain Plan --------------------------------------------------------------...7 SELECT STATEMENT (COST=2620 CARD=2576 BYTES=172592 IO_COST=2620 ) ...6 .HASH JOIN (COST=2620 CARD=2576 BYTES=172592 IO_COST=2620 ) ...4 ..VIEW OF 'SYS.VW_NSO_1' (COST=1794 CARD=6146 BYTES=122920 ) ...3 ...FILTER ...2 ....SORT (GROUP BY) (COST=1794 CARD=6146 BYTES=79898 IO_COST=1794 ) ...1 .....TABLE ACCESS (FULL) OF 'RANDY.PUB78' (COST=673 CARD=614578 BYTES=7989514 IO_COST=673 ) ...5 ..TABLE ACCESS (FULL) OF 'RANDY.PUB78' (COST=673 CARD=614578 BYTES=28885166 IO_COST=673 ) While the two full-table scans on PUB78 would typically arouse concern, this output indicates that over half of the query run-time is a result of the GROUP BY operation, substantially more than the total elapsed time for both fulltable scans. To get a trace of your own SQL session, the following statements should be included preceding the SQL under analysis: alter session set tracefile_identifier='RC_PROF'; alter session set sql_trace=TRUE; To also see wait events (recommended!) use this alternative invocation, instead: alter session set tracefile_identifier='RC_PROF'; alter session set events '10046 trace name context forever, level 8'; Look for files with the tracefile_identifier (in this case, RC_PROF) in the user_dump_dest directory, and apply those files to the formatter of your choice according to its documented procedures.
RDBMS software upgrade. Just as hints can mask downside performance issues, they can equally as well mask dramatic, upside performance opportunities that are delivered in nearly every new Oracle release. Hints inhibit portability. The really fast results you could achieve by fully hinting queries on your development system might not be reproduced successfully in every environment. Differences in hardware, OS configuration and database configuration can cause a hinted query to run terribly poorly when ported to a different environment. Hints are inscrutable. Mere presence of hints is sure to decrease readability and pertinence of a query to any developer or business analyst. The clutter of hints in a query might help the CBO work faster, but it wont help people work faster. Hints cover up sloppy practices. Pervasive use of hints on a database likely is symptomatic of deeper, unresolved issues. These include stale or missing object statistics, suboptimal database configuration, poorly written queries and even deficient application or database design. So, after writing a hint, take a hint: fix the root cause! The bottom line is that hints impose unnatural rigidity on the cost-based optimizer. Rigidity can be helpful during diagnosis of a problem, but in the long run, it can be profoundly detrimental to the scalability and adaptability of your environment.
Alternatives to Hints
Think of most hints as analogous to diapers, crutches, debuggers or training wheels they are indispensable in the short run, but you certainly wouldnt choose to use them all of the time! So, once youve obtained satisfactory performance from a problem query using a hint, what is the next step? 1) Be sure that all tables participating in the problem query have current statistics. Run DBMS_STATS to gather new statistics, if necessary. Unless the tables are immense, specify computed, rather than estimated statistics. Be sure that all indexes also have current statistics. Then, evaluate the problem query again without the hint. 2) [DBA] Confirm that system statistics are periodically measured and recorded. See MetaLink Note 149560.1 [6j] 3) Attempt to adjust session CBO parameters instead of, or in combination with, using hints. Consult this list of parameters used by the optimizer, understand them and adjust them appropriately: optimizer_mode optimizer_index_caching (default value is usually deficient, see [2]) optimizer_index_cost_adj (default value is often deficient, see [2]) optimizer_dynamic_sampling optimizer_max_permutations hash_join_enabled db_file_multiblock_read_count (used differently between Oracle8i and Oracle9i) sort_area_size and hash_area_size (Oracle8i and prior) 4) [DBA] Ensure that database CBO spfile parameters, especially optimizer_mode, compatible, optimizer_features_enable, optimizer_index_caching and optimizer_index_cost_adj, are established for optimal benefit to the entire instance. 5) Carefully observe the cardinality values in the querys EXPLAIN PLAN and 10053 trace. If there is a data distribution (skew) issue, consider gathering statistics for column histograms. 6) If possible, consider expressing the query differently. The CBO is rarely confounded by the mere order of tables in a FROM list or by predicate order or transitivity. Increasingly, it has the ability to recognize and transform specific suboptimal constructions such as OR predicates. Nevertheless, expressing lengthy or complex queries in an entirely different way sometimes results in improvements to the execution plan.
Conclusion
Query hints provide a convenient, ready-to-use means to manipulate the cost-based optimizer for a specific problem query. Hints can be useful for debugging a database or application issue, for testing SQL performance scenarios, and for learning how the optimizer works. With discipline and restraint, hints can even be used for advantage in production environments. Because hints constrain the optimizers freedom to explore a full range of execution plans, they inhibit scalability and optimal performance when they remain in a SQL statement over a period of time. Therefore, hints should not be regarded as a solution to performance issues, but they should be considered as an important tool for achieving top query performance.
References
[1] Breitling, Wolfgang; A Look Under the Hood of CBO: The 10053 Event. http://www.centrexcc.com [2] Gorman, Tim; The Search for Intelligent Life in the Cost-Based Optimizer. http://www.evdbt.com [3] Green, Connie Dialeris; Oracle9i Database Performance Tuning Guide and Reference, Release 2 (9.2), Chapter 5. October 2002, Oracle Corporation Part No. A96533-02. [4] Harrison, Guy; Oracle SQL High-Performance Tuning, Second Edition. 2001 Prentice-Hall, ISBN: 0-13012381-1. [5] Holdsworth, Andrew; Oracle9i Database Performance Planning. March 2002, Oracle Corporation Part No. A96532-01. [6] Oracle Support Site (subscription required). http://metalink.oracle.com. Resources: [6a] Note: 29236.1 QREF: SQL Statement Hints [6b] Note: 50607.1 How to specify and index hint [6c] Note: 62364.1 Hints and subqueries [6d] Note: 69992.1 Why is my hint ignored? [6e] Note: 73489.1 Affect of Number of Tables on Join Order Permutations [6f] Note: 122812.1 How to Tune a Query that Cannot be Modified [6g] Note: 225598.1 How to Obtain Tracing of Optimizer Computations (EVENT 10053) [6h] Note: 35934.1 Cost Based Optimizer - Common Misconceptions and Issues [6i] Note: 224270.1 Trace Analyzer: Interpreting Raw SQL Traces Generated by Event 10046 [6j] Note: 149560.1 Collect and Display System Statistics (CPU and IO) for CBO usage