Join elimination works fine when joining two tables:
SQL> set lines 200;
SQL> 
SQL> select * from v$version;
BANNER                                                                               CON_ID                                                                                                             
-------------------------------------------------------------------------------- ----------                                                                                                             
Oracle Database 12c Release 12.1.0.1.0 - 64bit Production                                 0                                                                                                             
PL/SQL Release 12.1.0.1.0 - Production                                                    0                                                                                                             
CORE    12.1.0.1.0  Production                                                                0                                                                                                             
TNS for Linux: Version 12.1.0.1.0 - Production                                            0                                                                                                             
NLSRTL Version 12.1.0.1.0 - Production                                                    0                                                                                                             
SQL> 
SQL> create table t01 (
  2    id integer,
  3    apk varchar2(255 char),
  4    constraint pk_01 primary key (id)
  5  );
Tabelle wurde erstellt.
SQL> create table t02 (
  2    id integer,
  3    apk varchar2(255 char),
  4    id_t01 integer,
  5    constraint pk_02 primary key (id),
  6    constraint fk_02 foreign key (id_t01) references t01(id)
  7  );
Tabelle wurde erstellt.
SQL> create table t03 (
  2    id integer,
  3    apk varchar2(255 char),
  4    id_t02 integer,
  5    constraint pk_03 primary key (id),
  6    constraint fk_03 foreign key (id_t02) references t02(id)
  7  );
Tabelle wurde erstellt.
SQL> create index ix_t03 on t03(id_t02);
Index wurde erstellt.
SQL> create index ix_t02 on t02(id_t01);
Index wurde erstellt.
SQL> insert into t01 (id, apk)
  2  select level, to_char(level)
  3  from dual
  4  connect by level <= 1000;
1000 Zeilen erstellt.
SQL> insert into t02(id, apk, id_t01)
  2  select id, apk, id from t01;
1000 Zeilen erstellt.
SQL> insert into t03(id, apk, id_t02)
  2  select id, apk, id from t01;
1000 Zeilen erstellt.
SQL> commit;
Transaktion mit COMMIT abgeschlossen.
SQL> 
SQL> exec dbms_stats.gather_table_stats(null, 'T01', method_opt=>'for all columns size skewonly', cascade=>true);
PL/SQL-Prozedur erfolgreich abgeschlossen.
SQL> exec dbms_stats.gather_table_stats(null, 'T02', method_opt=>'for all columns size skewonly', cascade=>true);
PL/SQL-Prozedur erfolgreich abgeschlossen.
SQL> exec dbms_stats.gather_table_stats(null, 'T03', method_opt=>'for all columns size skewonly', cascade=>true);
PL/SQL-Prozedur erfolgreich abgeschlossen.
SQL> commit;
Transaktion mit COMMIT abgeschlossen.
SQL> 
SQL> set autotrace traceonly explain;
SQL> 
SQL> select t02.id
  2  from t02
  3  left join t01 on t01.id = t02.id_t01;
Ausführungsplan
----------------------------------------------------------                                                                                                                                              
--------------------------------------------------------------                                                                                                                                          
| Id  | Operation            | Name  | Rows  | Bytes | Cost  |                                                                                                                                          
--------------------------------------------------------------                                                                                                                                          
|   0 | SELECT STATEMENT     |       |  1000 |  8000 |     2 |                                                                                                                                          
|   1 |  INDEX FAST FULL SCAN| PK_02 |  1000 |  8000 |     2 |                                                                                                                                          
--------------------------------------------------------------                                                                                                                                          
--> A fast full scan on the primary key index of t02 takes place, t01 is not read. This is what I am expecting.
Joining t02 and t03 also works as expected:
SQL> 
SQL> select t03.id
  2  from t03
  3  left join t02 on t02.id = t03.id_t02;
Ausführungsplan
----------------------------------------------------------                                                                                                                                              
--------------------------------------------------------------                                                                                                                                          
| Id  | Operation            | Name  | Rows  | Bytes | Cost  |                                                                                                                                          
--------------------------------------------------------------                                                                                                                                          
|   0 | SELECT STATEMENT     |       |  1000 |  8000 |     2 |                                                                                                                                          
|   1 |  INDEX FAST FULL SCAN| PK_03 |  1000 |  8000 |     2 |                                                                                                                                          
--------------------------------------------------------------                                                                                                                                          
--> A fast full scan on the primary key index of t03 takes place, t02 is not read. This is what I am expecting.
The problem arises when I am trying to join t01, t02 and t03:
SQL> select t03.id
  2  from t03
  3  left join t02 on t02.id = t03.id_t02
  4  left join t01 on t01.id = t02.id_t01;
Ausführungsplan
----------------------------------------------------------                                                                                                                                              
------------------------------------------------------------                                                                                                                                            
| Id  | Operation          | Name  | Rows  | Bytes | Cost  |                                                                                                                                            
------------------------------------------------------------                                                                                                                                            
|   0 | SELECT STATEMENT   |       |  1000 | 16000 |    18 |                                                                                                                                            
|   1 |  NESTED LOOPS OUTER|       |  1000 | 16000 |    18 |                                                                                                                                            
|   2 |   TABLE ACCESS FULL| T03   |  1000 |  8000 |    18 |                                                                                                                                            
|   3 |   INDEX UNIQUE SCAN| PK_02 |     1 |     8 |     0 |                                                                                                                                            
------------------------------------------------------------                                                                                                                                            
I would expect (only) a full index scan on pk_03 here, but the execution plan performs a nested loop between T03 and PK02.
What am I doing wrong? Do I have wrong expectations? I could not find anything in the Oracle documentation / stackoverflow / google that explains this behaviour.
The actual database I am working with does have more columns / tables etc., this is just a minimum example. The problem gets worse when joining twenty tables and the expected join elimination does not take place. This has quite a negative impact on our query execution times.
Thank you very much.
 
    