Ora Hints on Hints

Embed Size (px)

Citation preview

  • 8/4/2019 Ora Hints on Hints

    1/6

    Database

    HHINTSINTSONON HHINTINGINTING

    Jonathan Lewis, JL Computer Consultancy

    THEPROBLEMWITHHINTS

    Hints give us the opportunity to direct the optimizer away from the path it would take by defaultand there are several kinds of hints to help us. Some hints are strategic, some are for featurecontrol, some are for micro management, some are used to adjust the optimizers arithmeticand some control run-time behavior.

    The trouble with hints, though, is that they are badly documented and very few people reallyknow how to use them well. Consequently they are badly understood and it is very easy to makemistakes while hinting. Because of this, I generally advise people to avoid hinting in productionsystems and, if they do decide that hints are necessary, to stick to just the feature and

    strategic hints. In this document, though, I want to give you some ideas about how hints reallywork, what some of the more popular ones mean, and how to minimize the risk of using them.

    AREHINTSHINTS ?

    The name hint is a bad one. An Oracle hint is an order to the optimizer (or, just occasionally,to the run-time engine) that mustbe obeyed if it is legal.

    There are reasons, though, why Oracle may appear to ignore hints. When using a hint you mayhave made a simple spelling or syntax error (and the correct syntax can change with Oracleversion), you could be using the hint in a context where it is meaningless, you may have builtseveral contradictory hints into a statement with the result that Oracle ignores all the hintswhich are not self-consistent and, finally, there are some Oracle bugs which result in hints

    disappearing. But if you can get your hints right, Oracle must obey them.One of the more interesting context reasons for Oracle ignoring your hints is the use of theparameter (new to 10g):

    alter session set _optimizer_ignore_hints = true;

    (You could also do this at the system level or in the parameter file). If you have a lot of time fortesting when you upgrade Oracle versions, heres an interesting exercise to consider: how aboutdoing a test run with all hints disabled to find out which statements no longer need hinting andthen remove the redundant hints from the code. (I believe that hints in sys-recursive SQL are notignored when this parameter is set to true, and stored outlines and SQL profiles will still work. but that belief is based on just a couple of quick tests.)

    But if hints are really orders that cannot be ignored, why do some many people think that

    Oracle can ignore them? The answer is that we dont have the information we need tounderstand exactly what even the simplest hints mean. Consider, for example, the simpleparallelhint.

    I have a table which is list-partitioned on a column calledpt_group, with a local index oncolumns (n1, n2). I put aparallel hint into a particular query, and the optimizer appears to ignoreit:select

    /*+ parallel(t1,2) */{list of columns}

    fromt1

    1 Session #239

  • 8/4/2019 Ora Hints on Hints

    2/6

    Database

    wheret1.n1 = 5

    and t1.n2 = 10and t1.pt_group in (0,10);

    .|Id|Operation |Name |Cost |Pstart| Pstop|| 0|SELECT STATEMENT | | 48| | || 1| PARTITION LIST INLIST | | 48|KEY(I)|KEY(I)||*2| TABLE ACCESS BY LOCAL INDEX ROWID|T1 | 48|KEY(I)|KEY(I)||*3| INDEX RANGE SCAN |T1_I1| 3|KEY(I)|KEY(I)|

    Has the optimizer ignored my hint? The answer is no, and we could prove that by examining the10053 trace file. However, its rarely necessary to turn to the 10053 trace file, when a couple ofsimple tests will show us whats going on.

    Notice that the query is expected to run serially using an inlist iteratorto access somepartitions through the local index take a quick look at the cost (48) of this access path, and

    then add a hint to the query to block the use of any indexes on the table:

    select/*+ full(t1) parallel(t1,2) */{list of columns}

    fromt1

    wheret1.n1 = 5

    and t1.n2 = 10and t1.pt_group in (0,10);

    .| Id| Operation |Name |Cost |Pstart|Pstop | TQ |IN-OUT|PQ Distrib|| 0| SELECT STATEMENT | | 94 | | | | | || 1| PX COORDINATOR | | | | | | | || 2| PX SEND QC (RANDOM)|:TQ10| 94 | | |Q1,00| P->S |QC (RAND) || 3| PX BLOCK ITERATOR | | 94 |KEY(I)|KEY(I)|Q1,00| PCWC | ||* 4| TABLE ACCESS FULL|T1 | 94 |KEY(I)|KEY(I)|Q1,00| PCWP | |

    With the addition of the full(t1) hint we get a full tablescan (after all, Oracle has to obey thehint), and the tablescan should run as a parallel tablescan. But notice that the cost has gone upto 94.

    Now lets take out the full(t1) hint, and change the hinted degree of parallelism from two to four:select

    /*+ parallel(t1,4) */{list of columns}

    fromt1

    wheret1.n1 = 5

    and t1.n2 = 10and t1.pt_group in (0,10);

    .| Id| Operation |Name |Cost |Pstart|Pstop | TQ |IN-OUT|PQ Distrib|

    2 Session #239

  • 8/4/2019 Ora Hints on Hints

    3/6

    Database

    | 0| SELECT STATEMENT | | 47| | | | | || 1| PX COORDINATOR | | | | | | | || 2| PX SEND QC (RANDOM)|:TQ10| 47 | | |Q1,00| P->S |QC (RAND) || 3| PX BLOCK ITERATOR | | 47 |KEY(I)|KEY(I)|Q1,00| PCWC | ||* 4| TABLE ACCESS FULL|T1 | 47 |KEY(I)|KEY(I)|Q1,00| PCWP | |

    Again, we see a tablescan appearing unhinted that Oracle expects to run in parallel. Notice,though, that the cost of this path is now 47 just a little bit less than the cost of the serial indexaccess path.

    The hintparallel(t1, N) does nottell Oracle to run the query in parallel at degree N it tells theoptimizer that when it is calculating the cost of a tablescan on table t1 it should cost for paralleldegree N, and if that plan then happens to be the cheapest of all the plans to consider thatthats the plan to use.

    In this example, the cost of a tablescan at degree two is 94, which is more than the cost of theindexed access path at 48 which is why Oracle will only take the tablescan if we force thetablescan with the full hint. But when we indicate a degree of four the cost of the tablescan at

    degree four is slightly less than the cost of the serial index path, so Oracle takes it withoutneeding to be forced into the tablescan.

    Theparallel hint tells Oracle to change the arithmetic it doesntforce Oracle to run parallel andit isnt supposedto force Oracle to run parallel.

    FEATURE HINTS

    In 10g, we see more and more hints that I call the featurehints. As the Oracle developers andprogrammers add a new feature to the optimizers list of tricks they often seem to add a pair ofmatching hints to go with the feature. You may have seen the new hash aggregation thatappeared in 10.2 to handle variants of the group by clause. In general its a good idea, but youcould be unlucky and find a few cases where it manages to introduce a performance problem.So, to go with the new feature, there are two new hints, one to force it to happen, and one to

    stop it happening: /*+ use_hash_aggregation */, and /*+ no_use_hash_aggregation */respectively.

    Its worth noting that in 11g theres a new view called v$sql_hintwhich lists all the hints, theversion they appeared in, and the version where they were firsts coded into stored outlines. Ifyou see some strange new behavior in a query, its worth checking this view to see if you candiscover any hints that look as if they might be related to the feature.

    STRATEGY HINTS

    There are a few hints that allow you to dictate the overall strategy that you want Oracle to take.I call these the strategy hints, and the small number of hints I put into this list usually come inpairs:

    unnest / no_unnest push_subq / no_push_subq

    merge / no_merge

    push_pred / no_push_pred

    driving_site

    These are the hints I am happy to use on production systems, as they allow me to impose ahigh-level shape on the way Oracle optimises a query without requiring me to micro-manageevery single detail of the query plan. Along with these hints, I also include the qb_name hint which appeared in 10g to allow you to give names to query blocks.

    3 Session #239

  • 8/4/2019 Ora Hints on Hints

    4/6

    Database

    These hints have the following effects

    Unnest /no_unnest: determine whether or not a subquery should operate as a subquery in thefinal transformed query (no_unnest), or whether it should be transformed into an inline view(unnest).

    Push_subq / no_push_subq: if you have subqueries that are notgoing to be unnested, shouldthey run as the very last steps of the query (no_push_subq the traditional behaviour), orshould they run at the first possible moment (push_subq).

    Merge / no_merge: if you use a complex view (e.g. aggregate view, or join view) in yourquery, should you rewrite the query to merge the tables in the view into a single from clausewith all the other tables (merge), or should you evaluate the view to produce a standaloneresult set and then join the result set to the remaining tables (no_merge).

    Push_pred / no_push_pred: If you have a non-mergeable view (possible because of ano_merge hint) in your query, how should you operate the join from other tables; should youcreate one large view result and join it once (no_push_pred) or should you push the joinpredicate down into the view definition and recreate the view result set for every driving row

    from another table (push_pred). Driving_site: When running distributed queries, one of the factors affecting performance is

    the network traffic. The optimizer does not consider network costs (despite various notes anddocuments that suggest otherwise) and will always operate a query from the local databaseby default. There are cases where it is more efficient to run the query at a remote site andthen pull the result set back to the local site. The driving_site hint allow use to specify wherethe query runs.

    In most cases, it is possible to use only these hints to produce a stable and efficient executionplan; although I will also use theparallel() andparallel_index() hints to force queries into parallelexecution.

    But, as I mentioned above, there is one other hint that I use with the strategy hints; the

    qb_name() hint that labels query blocks. Consider the following:select

    /*+qb_name(main)unnest(@subq2)no_unnest(@subq4)no_push_subq(@subq4)

    */{columns}

    fromt1, t3

    wheret1.n2 = 15

    and exists (select

    /*+ qb_name(subq2) */null

    from t2where t2.n1 = 15and t2.id = t1.id

    )and t3.n1 = t1.n1and t3.n2 = 15and exists (

    select

    4 Session #239

  • 8/4/2019 Ora Hints on Hints

    5/6

    Database

    /*+ qb_name(subq4) */null

    from t4where t4.n1 = 15and t4.id = t3.id

    );

    Note that I have three query blocks the main query, and two subqueries. I have added a hint toeach query block (and you can use this hint with insert, update, and so on, its not just queries)to give each query block a name; so I have named the main query block main, the subqueryagainst table t2 has the name subq2, the subquery against table t4 has the name subq4.

    Once the subqueries are named, I can start using fully-qualified hints which means I specifythe query block that a hint applies to as the first parameter to the hint; so, in the opening set ofhints, I have an unnest() hint, but this applies to the query block called subq2; the no_unnest()hint applies to query block subq4, and having blocked unnesting for subq4 Ive also used theno_push_subq() hint referencing subq4 in that hint to tell Oracle not to run it early.

    MICRO-MANAGEMENT

    In general the strategy hints (with the parallel and naming hints) are sufficient to solve mostproblems of execution plans. However there are a lot of hints that you can use to micro-manageexecution plans. I avoid these wherever possible as it can be very difficult to produce stableplans if you have to specify every detail.

    Consider this fragment of a plan:...

    NESTED LOOPTABLE ACCESS (FULL) OF T1TABLE ACCESS BY INDEX ROWID T2

    INDEX RANGE SCAN T2_IND_SECOND -- wrong index...

    While trying to improve the performance of the underlying query, we notice that the optimizer ischoosing the wrong index at this point in the plan, and decide it should be using an index calledt2_ind_first. So we add an index hint to the code:select /*+ index(t2 t2_ind_first) */

    (Note that this is the pre-10g form for an index hint. If youre going to use index hints, youshould get into the habit of specifying them by using the index description (list of columns) inthe hint, not the index name.)

    Unfortunately, this works correctly for a while and then one day a change in the data andstatistics makes Oracle choose the following path (which obeys our hint, but doesnt do what wewanted):

    ...HASH JOIN -- wrong join method

    TABLE ACCESS (FULL) OF T1

    TABLE ACCESS BY INDEX ROWID T2

    INDEX FULL SCAN T2_IND_FIRST -- right index, wrong access method.

    ...

    This is the problem of micro-management you have to do it 100% completely and correctly and very few people know enough about hints to do this properly.

    5 Session #239

  • 8/4/2019 Ora Hints on Hints

    6/6

    Database

    CONCLUSION

    Hints are badly documented, and not well understood. There are some hints that can be usedfairly safely to produce reasonably stable execution plans. There are many hints, though, thatare commonly used and abused without a full appreciation of the potential instability they

    introduce to a system.If you are going to use hints, you want to try to stick with the feature hints and the strategyhints and avoid the micro-management hints.

    6 Session #239