Outer Join with OR and Lateral View Decorrelation
July 6, 2016 Leave a comment
Use of ANSI SQL is a personal thing.
Historically I have not been a fan apart from where it makes things easier/possible.
This reticence was mainly due to optimizer bugs and limitations in the earlier days.
Recently I have been using it much more because I find that the developers I interact with prefer it / understand it better.
You might/should be aware that Oracle will rewrite ANSI SQL to an Oracle syntax representation, this transformation being listed in the optimizer trace file.
You might/should also be aware that Oracle outer join syntax does not allow OR or IN:
drop table t1; drop table t2; create table t1 as select floor((rownum+1)/2) col1 , case when mod(rownum,2) = 0 then 1 else 2 end col2 , 10 col3 from dual connect by rownum <= 20; create table t2 as select rownum col1 , case when mod(rownum,2) = 0 then 2 else 1 end col3 from dual connect by rownum <= 10; select * from t1 , t2 where t1.col1 = t2.col1 (+) and ((t1.col2 = 1 and t2.col3 (+) > t1.col3) or (t1.col2 = 2 and t2.col3 (+) < t1.col3)); ORA-01719: outer join operator (+) not allowed in operand of OR or IN
ANSI SQL remedies this:
alter session tracefile_identifier = 'domlg1'; alter session set events 'trace[rdbms.SQL_Optimizer.*]'; select * from t1 left join t2 on t1.col1 = t2.col1 and ((t1.col2 = 1 and t2.col3 > t1.col3) or (t1.col2 = 2 and t2.col3 < t1.col3)); alter session set events 'trace off';
But it comes at a price.
Note the execution plan:
---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 20 | 1300 | 42 (0)| 00:00:01 | | 1 | NESTED LOOPS OUTER | | 20 | 1300 | 42 (0)| 00:00:01 | | 2 | TABLE ACCESS FULL | T1 | 20 | 780 | 2 (0)| 00:00:01 | | 3 | VIEW | | 1 | 26 | 2 (0)| 00:00:01 | |* 4 | TABLE ACCESS FULL| T2 | 1 | 26 | 2 (0)| 00:00:01 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter("T1"."COL1"="T2"."COL1" AND ("T1"."COL2"=1 AND "T2"."COL3">"T1"."COL3" OR "T1"."COL2"=2 AND "T2"."COL3"<"T1"."COL3"))
Now, maybe you will have better luck than me but no matter what I try I cannot change the NESTED LOOPS OUTER operation (I could rewrite it to do two joins rather than one and remove the OR).
So, if that lateral view involves some full table scans or other significant operations, they might be very expense on the outer operation of a nested loop.
The reason is in the optimizer trace.
Query after View Removal ******* UNPARSED QUERY IS ******** SELECT "T1."COL1" "COL1", "T1."COL2" "COL2", "T1."COL3" "COL3", "VW_LAT_AE9E49E8"."ITEM_1_0" "COL1", "VW_LAT_AE9E49E8"."ITEM_2_1" "COL3" FROM "DOM"."T1" "T1", LATERAL( (SELECT "T2"."COL1" "ITEM_1_0", "T2"."COL3" "ITEM_2_1" FROM "DOM"."T2" "T2" WHERE "T1"."COL1"="T2"."COL1" AND ("T1"."COL2"=1 AND "T2"."COL3">"T1"."COL3" OR "T1"."COL2"=2 AND "T2"."COL3" < "T1"."COL3"))) (+) "VW_LAT_AE9E49E8" DCL:Checking validity of lateral view decorrelation SEL$BCD4421C (#1) DCL: Bypassed: view has non-well-formed predicate DCL: Failed decorrelation validity for lateral view block SEL$BCD4421C (#1)
The OR prevents the decorrelation which seems to mean that we’re stuck with a NESTED LOOP for now.
Further Reading on ANSI:
Oracle Optimizer Blog
Jonathan Lewis on ANSI Outer
Jonathan Lewis on ANSI
Recent Comments