Skip to Main Content
  • Questions
  • Optimizer chooses an unsafe path: can this be considered a bug?

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Mauro.

Asked: April 06, 2023 - 7:15 am UTC

Last updated: April 12, 2023 - 11:59 pm UTC

Version: 12.2 - 19

Viewed 10K+ times! This question is

You Asked

Let us consider a case like this:

select ...
from ...
where sqrt ( col1 ) > 100
and col1 > 0;

From a logical point of view I think it is a perfectly legitimate query: I described a result I want and it is up to Oracle to retrieve it the way it deems best.
However, if the optimizer chooses to apply the former condition before the latter an error is returned when it rans into the first negative number.
Can this behaviour be considered a bug?
I would say yes but I would really like some expert opinion.
The reason of this question of mine is not academic: I ran really in such a case ( slightly more complex ) where an error is returned only because the optimizer chooses the wrong order of filters.
I have opened a SR ( 3 months ago !!! ) supplying a full test case, completely reproducible on 12.2 and 19 versions and I got a really unsatisfactory answer.
Ought the optimizer not be smart enough to not choose a potentially unsafe path or did my strong liking of Oracle lead me into overestimate its capabilities?
Sorry for my poor English which is not good as I wish, I am not a native speaker
Regards
Mauro

and Connor said...

There is no guaranteed order in which the database will execute predicates (and you cannot assume such).

We *used* to have an hint called ORDERED_PREDICATES which would allow control over this, but we removed it, because there are so many transformations that might occur which could re-sequence the way predicates are used and applied.

There's more examples of that here

https://asktom.oracle.com/pls/apex/asktom.search?tag=predicate-evaluation-order

In this particular case, you could provide safety with

select ...
from ...
where sqrt ( least(col1,0) ) > 100
and col1 > 0;

Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

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.
Connor McDonald
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


Connor McDonald
April 12, 2023 - 11:59 pm UTC

I agree we should add some emphasis to this in the manuals.


More to Explore

SQL

The Oracle documentation contains a complete SQL reference.