All three variants are valid and possible, eg
SQL> create table t1 as select * from dba_objects;
Table created.
SQL> create table t2 as select * from dba_objects;
Table created.
SQL> create table t3 as select * from dba_objects;
Table created.
SQL>
SQL> create index ix1 on t1 ( object_id );
Index created.
SQL> create index ix2 on t2 ( object_id );
Index created.
SQL> create index ix3 on t3 ( object_id );
Index created.
SQL>
SQL> set autotrace traceonly explain
--
-- default is a hash join for all
--
SQL> select *
2 from t1, t2, t3
3 where t1.object_id = t2.object_id
4 and t2.object_id = t3.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 1487401159
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 78268 | 29M| | 3901 (1)| 00:00:01 |
|* 1 | HASH JOIN | | 78268 | 29M| 10M| 3901 (1)| 00:00:01 |
| 2 | TABLE ACCESS FULL | T3 | 78284 | 9M| | 425 (1)| 00:00:01 |
|* 3 | HASH JOIN | | 78275 | 19M| 10M| 1919 (1)| 00:00:01 |
| 4 | TABLE ACCESS FULL| T2 | 78283 | 9M| | 425 (1)| 00:00:01 |
| 5 | TABLE ACCESS FULL| T1 | 78282 | 9M| | 425 (1)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
3 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
Note
-----
- this is an adaptive plan
SQL>
SQL>
--
-- this *looks* like it is inavlid/ignored, but see the last example for a reason why
--
SQL> select /*+ use_nl(t1) */ *
2 from t1, t2, t3
3 where t1.object_id = t2.object_id
4 and t2.object_id = t3.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 1573120526
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 78268 | 29M| | 3901 (1)| 00:00:01 |
|* 1 | HASH JOIN | | 78268 | 29M| 10M| 3901 (1)| 00:00:01 |
| 2 | TABLE ACCESS FULL | T3 | 78284 | 9M| | 425 (1)| 00:00:01 |
|* 3 | HASH JOIN | | 78275 | 19M| 10M| 1919 (1)| 00:00:01 |
| 4 | TABLE ACCESS FULL| T1 | 78282 | 9M| | 425 (1)| 00:00:01 |
| 5 | TABLE ACCESS FULL| T2 | 78283 | 9M| | 425 (1)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
3 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
Note
-----
- this is an adaptive plan
SQL>
SQL> select /*+ use_nl(t1 t2) */ *
2 from t1, t2, t3
3 where t1.object_id = t2.object_id
4 and t2.object_id = t3.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 745910267
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 78268 | 29M| | 158K (1)| 00:00:07 |
| 1 | NESTED LOOPS | | 78268 | 29M| | 158K (1)| 00:00:07 |
| 2 | NESTED LOOPS | | 78276 | 29M| | 158K (1)| 00:00:07 |
|* 3 | HASH JOIN | | 78276 | 19M| 10M| 1919 (1)| 00:00:01 |
| 4 | TABLE ACCESS FULL | T2 | 78283 | 9M| | 425 (1)| 00:00:01 |
| 5 | TABLE ACCESS FULL | T3 | 78284 | 9M| | 425 (1)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IX1 | 1 | | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 132 | | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
6 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
Note
-----
- this is an adaptive plan
SQL>
SQL> select /*+ use_nl(t1 t2 t3) */ *
2 from t1, t2, t3
3 where t1.object_id = t2.object_id
4 and t2.object_id = t3.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 1859668671
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 78268 | 29M| 313K (1)| 00:00:13 |
| 1 | NESTED LOOPS | | 78268 | 29M| 313K (1)| 00:00:13 |
| 2 | NESTED LOOPS | | 78275 | 29M| 313K (1)| 00:00:13 |
| 3 | NESTED LOOPS | | 78275 | 19M| 157K (1)| 00:00:07 |
| 4 | TABLE ACCESS FULL | T1 | 78282 | 9M| 425 (1)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID BATCHED| T2 | 1 | 132 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IX2 | 1 | | 1 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | IX3 | 1 | | 1 (0)| 00:00:01 |
| 8 | TABLE ACCESS BY INDEX ROWID | T3 | 1 | 132 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
7 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
--
-- the first example didnt use the nested loop because it was saying, if "t1" is not the "starting" table, then drive into with a nested loop.
-- But t1 *was* the starting table, so the hint did not apply, hence the hash join. By saying that t2 is the leading (starting) table,
-- then the hint now comes into play
--
SQL>
SQL> select /*+ leading(t2) use_nl(t1) */ *
2 from t1, t2, t3
3 where t1.object_id = t2.object_id
4 and t2.object_id = t3.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 745910267
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 78268 | 29M| | 158K (1)| 00:00:07 |
| 1 | NESTED LOOPS | | 78268 | 29M| | 158K (1)| 00:00:07 |
| 2 | NESTED LOOPS | | 78276 | 29M| | 158K (1)| 00:00:07 |
|* 3 | HASH JOIN | | 78276 | 19M| 10M| 1919 (1)| 00:00:01 |
| 4 | TABLE ACCESS FULL | T2 | 78283 | 9M| | 425 (1)| 00:00:01 |
| 5 | TABLE ACCESS FULL | T3 | 78284 | 9M| | 425 (1)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | IX1 | 1 | | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 132 | | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")
6 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
Note
-----
- this is an adaptive plan
SQL>