Monday, June 23, 2014

How to specify SQL Hints in Oracle correctly


As we know, Oracle honors the hints as long as they are properly specified. The catch phrase here is "properly specified." If you don't specify the hints properly, Oracle simply ignores the hints without any errors or warnings which can be quite frustrating. We all have our favorite stories about hints not being honored by Oracle. We all have tried and tried so many permutations and combinations to make the hints work, but Oracle somehow stubbornly ignores our hints. But that's not Oracle's fault! You need to specify the hints properly. Otherwise, Oracle will simply ignore them. The following are few useful tips that would help you specify hints properly.

Useful Tips
  • Syntax - You must specify hints within /*+   <hint>   */
  • Case-insensitive - Hints are not case sensitive so you don't need to worry about upper or lower case.
  • Incorrect names - If names of the tables or indexes are not correct in the hints or have typos in them, Oracle will simply ignore the hints.
  • Availability of access path - If you specify a hint for an access path which is not available, then Oracle simply ignores the hint. For example, if you specify an index hint, but there are no indexes on the table, then Oracle will simply ignore the hint.
  • Join hints - Inner table and outer table must be specified properly. Otherwise hints may not work.

How to correctly specify Nested Loop Join Hint

If you want Oracle to use nested loop join method, then you need to specify the hint as /*+ leading(outer_table)  use_nl (inner_table) */. You may be fine with only use_nl  (inner_table) hint, but to leave nothing to doubt, you should specify leading (outer_table) hint as well. Let's take an example.

As shown below, the un-hinted execution plan uses hash join.

SELECT *
FROM T1, T2
WHERE T1.ID = T2.T1_ID                                                   

-----------------------------------                                                           
| Id  | Operation          | Name |                                                           
-----------------------------------                                                           
|   0 | SELECT STATEMENT   |      |                                                           
|   1 |  HASH JOIN         |      |                                                           
|   2 |   TABLE ACCESS FULL| T1   |                                                           
|   3 |   TABLE ACCESS FULL| T2   |                                                           
-----------------------------------                                                           

If you need nested loop join method on tables t1 and t2, then specify the hint as follows. Note that T1 is the inner table or row source and T2 is the outer table or row source.

SELECT /*+ leading(t2) use_nl(t1) */ *
FROM T1, T2
WHERE T1.ID = T2.T1_ID                                                                                      

-----------------------------------                                                           
| Id  | Operation          | Name |                                                           
-----------------------------------                                                           
|   0 | SELECT STATEMENT   |      |                                                           
|   1 |  NESTED LOOPS      |      |                                                           
|   2 |   TABLE ACCESS FULL| T2   |                                                           
|   3 |   TABLE ACCESS FULL| T1   |                                                           
-----------------------------------                                                           


If you need a nested loop join method with T2 as inner table and T1 as outer table, then specify hint as follows:

SELECT /*+ leading(t1) use_nl(t2) */ *
FROM T1, T2
WHERE T1.ID = T2.T1_ID                                                                                      

-----------------------------------                                                           
| Id  | Operation          | Name |                                                           
-----------------------------------                                                           
|   0 | SELECT STATEMENT   |      |                                                           
|   1 |  NESTED LOOPS      |      |                                                           
|   2 |   TABLE ACCESS FULL| T1   |                                                           
|   3 |   TABLE ACCESS FULL| T2   |                                                           
-----------------------------------                                                           


How to correctly specify Nested Loop (Semi) Join Hint - EXISTS Query

If you want to force nested loop (semi) join method, then you need to specify /*+ use_nl (inner_table) */ in the sub-query. Let's take an example. The below is un-hinted execution plan.

SELECT *
FROM T1
WHERE EXISTS ( SELECT 'x'                
               FROM T2                            
               WHERE T1.ID = T2.T1_ID )                                                           

-----------------------------------                                                           
| Id  | Operation          | Name |                                                           
-----------------------------------                                                           
|   0 | SELECT STATEMENT   |      |                                                           
|   1 |  HASH JOIN SEMI    |      |                                                           
|   2 |   TABLE ACCESS FULL| T1   |                                                           
|   3 |   TABLE ACCESS FULL| T2   |                                                           
-----------------------------------                                                           


To force nested loop (semi) join, please note how to specify leading and use_nl hints along with appropriate inner_table and outer_table.

SELECT /*+ leading(t1) */ *
FROM T1
WHERE EXISTS ( SELECT /*+ use_nl(t2) */ 'x'                
               FROM T2                
               WHERE T1.ID = T2.T1_ID )                                                                                    

-----------------------------------                                                           
| Id  | Operation          | Name |                                                           
-----------------------------------                                                           
|   0 | SELECT STATEMENT   |      |                                                           
|   1 |  NESTED LOOPS SEMI |      |                                                           
|   2 |   TABLE ACCESS FULL| T1   |                                                           
|   3 |   TABLE ACCESS FULL| T2   |                                                           
-----------------------------------                                                           


How to correctly specify Nested Loop (Semi) Join Hint - IN Queries

If you have a SQL with IN clause, as shown below, then use_nl hint must be specified within the inner query as shown below. Leading hint is specified in the outer query. The first example shows un-hinted statement while the second example shows hinted statement.

SELECT *
FROM t1
WHERE id IN ( SELECT t1_id FROM t2 )                           

-----------------------------------                                                           
| Id  | Operation          | Name |                                                           
-----------------------------------                                                           
|   0 | SELECT STATEMENT   |      |                                                           
|   1 |  HASH JOIN SEMI    |      |                                                           
|   2 |   TABLE ACCESS FULL| T1   |                                                           
|   3 |   TABLE ACCESS FULL| T2   |                                                           
-----------------------------------                                                           


SELECT /*+ leading(t1) */ * 
FROM t1
WHERE id IN ( SELECT /*+ use_nl(t2) */ t1_id              
              FROM t2 )                                                   

-----------------------------------                                                           
| Id  | Operation          | Name |                                                           
-----------------------------------                                                           
|   0 | SELECT STATEMENT   |      |                                                           
|   1 |  NESTED LOOPS SEMI |      |                                                           
|   2 |   TABLE ACCESS FULL| T1   |                                                           
|   3 |   TABLE ACCESS FULL| T2   |                                                           
-----------------------------------                                                           


How to correctly specify Nested Loop (anti) Join Hint  - NOT EXISTS Queries

The specifications for nested loop (anti) join hint are similar to nested loop (semi) join hint specifications. You must specify use_nl hint in the sub-query with inner table. The leading hint should be specified in the outer query. The first example shows un-hinted statement while the second example shows hinted statement.

SELECT  *
FROM T1
WHERE NOT EXISTS ( SELECT 'x'
                   FROM T2                    
                   WHERE T1.ID = T2.T1_ID )                                          

-----------------------------------                                                           
| Id  | Operation          | Name |                                                           
-----------------------------------                                                           
|   0 | SELECT STATEMENT   |      |                                                           
|   1 |  HASH JOIN ANTI    |      |                                                           
|   2 |   TABLE ACCESS FULL| T1   |                                                           
|   3 |   TABLE ACCESS FULL| T2   |                                                           
-----------------------------------                                                           


SELECT  /*+ leading(t1) */ *
FROM T1
WHERE NOT EXISTS ( SELECT /*+ use_nl(t2) */ 'x'                     
                   FROM T2                    
                   WHERE T1.ID = T2.T1_ID )                                                                            


-----------------------------------                                                           
| Id  | Operation          | Name |                                                           
-----------------------------------                                                           
|   0 | SELECT STATEMENT   |      |                                                           
|   1 |  NESTED LOOPS ANTI |      |                                                           
|   2 |   TABLE ACCESS FULL| T1   |                                                           
|   3 |   TABLE ACCESS FULL| T2   |                                                           
-----------------------------------                                                           













No comments:

Post a Comment