Mauro Papandrea, April 11, 2023 - 7:26 am UTC
I understand that Oracle is absolutely free to choose to execution path he likes more but only as long as it returns the required result.
However I think that it should be able to detect potentially unsafe paths and avoid them, or am I expecting too much from optimizer?
That is the real question: my special case is not so important, the problem is much more general: if it does not take care of the risks of unsafe paths then for each and every query we humans must make ourselves responsible that no unsafe path can exist and I feel this is something against the very idea of the declarativeness property of sql language ( and a very hard job too ).
And in that case this should be documented really well.
In the academical case your solution woudl work fine but I my real case I am afraid there is no such simple way ( however I am going to think of a way to adapt your idea to my real case ).
I do not think that removing that hint was a good idea: the mere presence would not imply the obligation to use it, just the possibility to use it in some extreme case as the one I ran into.
However, although it is no longer listed in the manual it is still there, at least right now ( up to 19c ), and it works.
Perhaps it is still better to use it instead of one there was never documented ( the materialized one ), as suggested by someone from support, what do you think?
Best regards
Mauro
Use CASE to force order of evaluation
Mike Tefft, April 11, 2023 - 8:03 pm UTC
To have control over the order of evaluation, use CASE. It is documented that CASE evaluates its clauses in order, and stops at the first clause that evaluates as true. So:
with kept_rows as
(select stuff,
case
when col1 <= 0 then 'No'
when sqrt(col1) <= 100 then 'No'
else 'Yes'
end as keep_me
from ...)
select * from kept_rows where keep_me = 'Yes' https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/CASE-Expressions.html#GUID-CA29B333-572B-4E1D-BA64-851FABDBAE96 Oracle Database uses short-circuit evaluation. .... For a searched CASE expression, the database evaluates each condition to determine whether it is true, and never evaluates a condition if the previous condition was true.
April 12, 2023 - 11:58 pm UTC
True, but you do need to be careful of impact here on index usage
Old trick: ROWNUM in subquery
mathguy, April 12, 2023 - 6:20 am UTC
The way you wrote the query, Oracle's behavior should not be considered a bug - it works as documented.
But consider this version:
select col1 from (select col1 from tbl where col1 > 0) where sqrt(col1) > 100;
This absolutely
should work, but it doesn't; Oracle combines the subquery and the outer query into a single one, and the result is not equivalent to the original.
I assume this (likely using a WITH clause) was your use case on which you were offered the recommendation to use the MATERIALIZE hint.
Instead, an old trick that looks like it shouldn't even work, but it does, is to add ROWNUM to the SELECT clause of the subquery:
select col1 from (select col1, rownum from tbl where col1 > 0) where sqrt(col1) > 100;
This does require that the predicates be divided between a subquery and an outer query, but again - I am guessing this was your use case from the beginning anyway.
Mauro Papandrea, April 12, 2023 - 7:57 am UTC
Thanks for your comments and for your suggestions.
As a matter of fact I was thinking something like those, using nvl/nvl2 in order to have a single condition.
However my general question stands: I think that potentially unsafe paths should be detected and avoided, otherwise the really nice idea of a declarative language is defeated: I describe what I want and Oracle is perfectly free to choose the way to give me what I want, very nice, I really like it.
But if it is not smart enough to avoid traps this burden falls back upon us and this is scaring.
And even if it is deemed right to be such, it ought really to be put in capital letters in the manuals.
Regards
April 12, 2023 - 11:59 pm UTC
I agree we should add some emphasis to this in the manuals.