Hello Listers, Recently I have got puzzled when I tried to read the following execution plan . The SQL was: explain plan for SELECT /*+ leading(A C@subq1) index(A SUPPLIER_SCHEDULE_UK) opt_param('_or_expand_nvl_predicate', 'FALSE') */ OBJID, OBJVERSION FROM IFSAPP.SUPPLIER_SCHEDULE A WHERE VENDOR_NO = NVL(:B5 ,VENDOR_NO) AND CONTRACT = NVL(:B4 , CONTRACT) AND PART_NO = NVL(:B3 , PART_NO) AND NVL(AGREEMENT_ID, '@') = NVL(:B2 , NVL(AGREEMENT_ID, '@')) AND SUPP_SCHEDULE_TYPE_DB = NVL(:B1 , SUPP_SCHEDULE_TYPE_DB) AND ---OBJSTATE IN ('Created', 'Out Of Tolerance', 'Tol Check In Process') OBJSTATE IN ('Superceded') AND CONTRACT IN (SELECT IFSAPP.USER_ALLOWED_SITE_API.AUTHORIZED(CONTRACT) FROM IFSAPP.USER_ALLOWED_SITE ) AND EXISTS (SELECT 1 FROM IFSAPP.SUPP_SCHED_AGREEMENT_PART B WHERE A.VENDOR_NO=B.VENDOR_NO AND A.CONTRACT=B.CONTRACT AND A.AGREEMENT_ID=B.AGREEMENT_ID AND A.PART_NO=B.PART_NO AND NVL(:B6 , B.APPROVER_ID) = B.APPROVER_ID ) AND A.SCHEDULE_NO = ( select /*+ qb_name(subq1) */ MAX(C.SCHEDULE_NO) FROM IFSAPP.SUPPLIER_SCHEDULE C where C.VENDOR_NO = A.VENDOR_NO AND C.CONTRACT = A.CONTRACT AND C.PART_NO = A.PART_NO AND C.SUPP_SCHEDULE_TYPE_DB = A.SUPP_SCHEDULE_TYPE_DB and rownum =1 ) ORDER BY VENDOR_NO, CONTRACT, PART_NO, SUPP_SCHEDULE_TYPE_DB DESC, SCHEDULE_NO ; Output of "explain plan for" was: ------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 110 | 609 (5)| 00:00:06 | | 1 | SORT ORDER BY | | 1 | 110 | 609 (5)| 00:00:06 | | 2 | NESTED LOOPS SEMI | | 1 | 110 | 603 (5)| 00:00:06 | |* 3 | TABLE ACCESS BY INDEX ROWID | SUPPLIER_SCHEDULE_TAB | 1 | 82 | 602 (5)| 00:00:06 | |* 4 | INDEX FULL SCAN | SUPPLIER_SCHEDULE_UK | 1 | | 601 (5)| 00:00:06 | |* 5 | INDEX FAST FULL SCAN | USER_ALLOWED_SITE_B_IX | 2 | 12 | 2 (0)| 00:00:01 | | 6 | SORT AGGREGATE | | 1 | 39 | | | | 7 | FIRST ROW | | 1 | 39 | 3 (0)| 00:00:01 | |* 8 | INDEX RANGE SCAN (MIN/MAX)| SUPPLIER_SCHEDULE_UK | 1 | 39 | 3 (0)| 00:00:01 | |* 9 | TABLE ACCESS BY INDEX ROWID | SUPP_SCHED_AGREEMENT_PART_TAB | 1 | 28 | 1 (0)| 00:00:01 | |* 10 | INDEX UNIQUE SCAN | SUPP_SCHED_AGREEMENT_PART_PK | 1 | | 0 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - filter("ROWSTATE"='Superceded' AND NVL("AGREEMENT_ID",'@')=NVL(:B2,NVL("AGREEMENT_ID",'@'))) 4 - filter("PART_NO"=NVL(:B3,"PART_NO") AND "SUPP_SCHEDULE_TYPE"=NVL(:B1,"SUPP_SCHEDULE_TYPE") AND "CONTRACT"=NVL(:B4,"CONTRACT") AND "VENDOR_NO"=NVL(:B5,"VENDOR_NO") AND EXISTS (SELECT /*+ */ 0 FROM IFSAPP."USER_ALLOWED_SITE_TAB" "USER_ALLOWED_SITE_TAB" WHERE "USER_ALLOWED_SITE_API"."AUTHORIZED"("CONTRACT")=:B1) AND "SCHEDULE_NO"= (SELECT /*+ QB_NAME ("SUBQ1")*/ MAX("SCHEDULE_NO") FROM IFSAPP."SUPPLIER_SCHEDULE_TAB" "SUPPLIER_SCHEDULE_TAB" WHERE "SUPP_SCHEDULE_TYPE"=:B2 AND "VENDOR_NO"=:B3 AND "CONTRACT"=:B4 AND "PART_NO"=:B5)) 5 - filter("USER_ALLOWED_SITE_API"."AUTHORIZED"("CONTRACT")=:B1) 8 - access("PART_NO"=:B1 AND "CONTRACT"=:B2 AND "VENDOR_NO"=:B3 AND "SUPP_SCHEDULE_TYPE"=:B4) 9 - filter("APPROVER_ID"=NVL(:B6,"APPROVER_ID")) 10 - access("AGREEMENT_ID"="AGREEMENT_ID" AND "VENDOR_NO"="VENDOR_NO" AND "CONTRACT"="CONTRACT" AND "PART_NO"="PART_NO") I could not interpret the right sequence of steps 4,5 and 6. After tracing the SQL with event 10046 I have got the following execution plan (from the trace file): Rows Row Source Operation ------- --------------------------------------------------- 0 SORT ORDER BY (cr=19954 pr=0 pw=0 time=343900 us) 0 NESTED LOOPS SEMI (cr=19954 pr=0 pw=0 time=343866 us) 0 TABLE ACCESS BY INDEX ROWID SUPPLIER_SCHEDULE_TAB (cr=19954 pr=0 pw=0 time=343841 us) 5022 INDEX FULL SCAN SUPPLIER_SCHEDULE_UK (cr=15701 pr=0 pw=0 time=322874 us)(object id 198167) 1 INDEX FAST FULL SCAN USER_ALLOWED_SITE_B_IX (cr=12 pr=0 pw=0 time=1368 us)(object id 9690) 5022 SORT AGGREGATE (cr=15066 pr=0 pw=0 time=112146 us) 5022 COUNT STOPKEY (cr=15066 pr=0 pw=0 time=93179 us) 5022 FIRST ROW (cr=15066 pr=0 pw=0 time=75120 us) 5022 INDEX RANGE SCAN (MIN/MAX) SUPPLIER_SCHEDULE_UK (cr=15066 pr=0 pw=0 time=62607 us)(object id 198167) 0 INDEX RANGE SCAN SUPP_SCHED_AGREEMENT_PART_UK (cr=0 pr=0 pw=0 time=0 us)(object id 198165) Clearly, here the first step was step 4 (INDEX FULL SCAN SUPPLIER_SCHEDULE_UK ), which is the Parent step of INDEX FAST FULL SCAN USER_ALLOWED_SITE_B_IX and SORT AGGREGATE steps . Afterwards I have changed slightly the sql statement , using the full/aliased object notation of CONTACT column Of IFSAPP.SUPPLIER_SCHEDULE A table (here I am providing only the changed lines: "CONTRACT IN" -> "A.CONTRACT IN" "IFSAPP.USER_ALLOWED_SITE_API.AUTHORIZED(CONTRACT)" -> "IFSAPP.USER_ALLOWED_SITE_API.AUTHORIZED(A.CONTRACT)"): ... A.CONTRACT IN (SELECT /*+ qb_name(subq2) */ IFSAPP.USER_ALLOWED_SITE_API.AUTHORIZED(A.CONTRACT) FROM IFSAPP.USER_ALLOWED_SITE S ) AND ... The "new" execution plan is now: ------------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 110 | 661 (5)| 00:00:06 | | 1 | SORT ORDER BY | | 1 | 110 | 661 (5)| 00:00:06 | | 2 | NESTED LOOPS SEMI | | 1 | 110 | 655 (5)| 00:00:06 | |* 3 | TABLE ACCESS BY INDEX ROWID | SUPPLIER_SCHEDULE_TAB | 1 | 82 | 654 (5)| 00:00:06 | |* 4 | INDEX FULL SCAN | SUPPLIER_SCHEDULE_UK | 1 | | 653 (5)| 00:00:06 | |* 5 | FILTER | | | | | | | 6 | INDEX FAST FULL SCAN | USER_ALLOWED_SITE_B_IX | 1 | | 2 (0)| 00:00:01 | | 7 | SORT AGGREGATE | | 1 | 39 | | | |* 8 | COUNT STOPKEY | | | | | | | 9 | FIRST ROW | | 1 | 39 | 3 (0)| 00:00:01 | |* 10 | INDEX RANGE SCAN (MIN/MAX)| SUPPLIER_SCHEDULE_UK | 1 | 39 | 3 (0)| 00:00:01 | |* 11 | INDEX RANGE SCAN | SUPP_SCHED_AGREEMENT_PART_UK | 1 | 28 | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------------------------- The only difference is the FILTER step between INDEX FULL SCAN on SUPPLIER_SCHEDULE_UK and INDEX FAST FULL SCAN on USER_ALLOWED_SITE_B_IX, but now the execution plan is (at least for me) Much more readable. My questions are : 1) Should I always trace (with event 10046 or 10053) the SQL to get the "full" (with all the steps) execution plan? 2) Is there any systematic "approach" (apart from trial & error) to reveal the hidden (the this case FLTER) steps ? 3) Why is "explain plan for" not able to ident properly parent/child steps ? Perhaps there is a Bug related to LEVEL pseudo variable when using CONNECT BY ? I am awaiting your comments impatiently ;) Best Regards. Milen P.S. There is no difference in the performance of both "versions" of this SQL -- //www.freelists.org/webpage/oracle-l