Everyone knows that rownum in inline views blocks many query transformations, for example pushing/pulling predicates, scalar subquery unnesting, etc, and many people use it for such purposes as a workaround to avoid unwanted transformations(or even CBO bugs).
If we pull the predicate “column_value = 3” from the following query to higher level
select * from (select * from table(odcinumberlist(1,1,1,2,2,2,3,3,3)) order by 1) where rownum <= 2 and column_value = 3; COLUMN_VALUE ------------ 3 3
we will get different results:
select * from (select * from (select * from table(odcinumberlist(1,1,1,2,2,2,3,3,3)) order by 1) where rownum <= 2 ) where column_value = 3; no rows selected
Doc ID 62340.1
But we recently encountered a bug with it: lateral view with ROWNUM returns wrong results in case of lateral view decorrelation.
Compare results of this query with and without no_decorrelation hint:
with t1(a) as (select * from table(odcinumberlist(1,3))) ,t2(b) as (select * from table(odcinumberlist(1,1,3,3))) ,t(id) as (select * from table(odcinumberlist(1,2,3))) select * from t, lateral(select/*+ no_decorrelate */ rownum rn from t1,t2 where t1.a=t2.b and t1.a = t.id )(+) order by 1,2; ID RN ---------- ---------- 1 1 1 2 2 3 1 3 2 |
with t1(a) as (select * from table(odcinumberlist(1,3))) ,t2(b) as (select * from table(odcinumberlist(1,1,3,3))) ,t(id) as (select * from table(odcinumberlist(1,2,3))) select * from t, lateral(select rownum rn from t1,t2 where t1.a=t2.b and t1.a = t.id )(+) order by 1,2; ID RN ---------- ---------- 1 1 1 2 2 3 3 3 4 |
Of course, we can draw conclusions even from these results: we can see that in case of decorrelation(query with hint) rownum was calculated before the join. But to be sure we can check optimizer’s trace 10053:
******* UNPARSED QUERY IS ******* SELECT VALUE(KOKBF$2) "ID", "VW_DCL_76980902"."RN" "RN" FROM TABLE("ODCINUMBERLIST"(1, 2, 3)) "KOKBF$2", (SELECT ROWNUM "RN_0", VALUE(KOKBF$0) "ITEM_3" FROM TABLE("ODCINUMBERLIST"(1, 3)) "KOKBF$0", TABLE("ODCINUMBERLIST"(1, 1, 3, 3)) "KOKBF$1" WHERE VALUE(KOKBF$0) = VALUE(KOKBF$1) ) "VW_DCL_76980902" WHERE "VW_DCL_76980902"."ITEM_3"(+) = VALUE(KOKBF$2) ORDER BY VALUE(KOKBF$2), "VW_DCL_76980902"."RN" *************************
I’ll modify it a bit just to make it more readable:
we can see that
select * from t, lateral(select rownum rn from t1,t2 where t1.a=t2.b and t1.a = t.id)(+) order by 1,2;
was transformed to
select t.id, dcl.rn from t, (select rownum rn from t1,t2 where t1.a=t2.b) dcl where dcl.a(+) = t.id order by 1,2;
And it confirms that rownum was calculated on the different dataset (t1-t2 join) without join filter by table t.
I created SR with Severity 1 (SR #3-19117219271) more than a month ago, but unfortunately Oracle development doesn’t want to fix this bug and moreover they say that is not a bug. So I think this is a dangerous precedent and probably soon we will not be able to be sure in the calculation of rownum and old fixes…