This is one of those posts where the investigation is left as an exercise – it’s not difficult, just something that will take a little time that I don’t have, and just might end up with me chasing half a dozen variations (so I’d rather not get sucked into looking too closely). It comes from an OTN question which ends up reporting this predicate:
WHERE ( LENGTH ( :b7) IS NULL OR UPPER (TRIM (CODFSC)) = UPPER (TRIM ( :b8)) or UPPER (TRIM (CODUIC)) = UPPER (TRIM ( :b9))) AND STATE = 0;
The three bind variables all hold the same value; there is a function-based index on upper(trim(codfsc)), and another on upper(trim(coduic)). The execution plan for this query is a full tablescan, but if you eliminate the first predicate Oracle can do a concatenation of two index range scans. This variation doesn’t surprise me, the optimizer’s ability to introduce concatenation is limited; however, I did wonder whether some small variation in the SQL would allow the optimizer to get just a little more clever.
Would you get concatenation if you changed the first predicate to (:b7 is null); if not, would a similar query that didn’t depend on function-based indexes do concatenation; if not is there any rewrite of this query that could do a tablescan ONLY for the case where :b7 was null ?
Demonstrations of any levels of success can be left in the comments if anyone’s interested. To get a fixed font that preserves space start the code with “sourcecode” and end with “/sourcecode” (removing the quotation marks and replacing them with square brackets).
Latest update – on the thread – by Franck Pachot.
The “use_concat” hint has been extended to include an “or_predicates(N)” parameter – the N identifies which of the query block predicates should be expanded, so it’s a little fragile, as well as being undocumented. This allows the original query to do the necessary expansion.
I keep forgetting that OR-expansion requires (by default) that there is an indexed-access option for each generated branch; and I also keep forgetting that the special “:bind is null” concatenation appears only (by default) for the special case of “columnX = nvl(:b1, columnX)”.
Comment by Jonathan Lewis — January 3, 2014 @ 11:47 am GMT Jan 3,2014 |
Hi Jonathan,
I’ve never been able to understand exactly how predicates in or_predicates() are numbered. For example:
generates the following outline when we have an index access for a, b and c:
but
generates
And there is also another use_concat attribute when predicates are reordered during optimization:
generates
Anyway, I’ll never use that in production. Rewriting the query so that each branch has an index access (such as with nvl or decode) is probably the best way when possible.
Regards,
Franck.
Comment by Franck Pachot — January 3, 2014 @ 2:44 pm GMT Jan 3,2014 |
Franck,
I’m guessing you have single column indexes on a, b, and c.
I’ve only ever had to play with “simple” examples – and then I’ve usually done “union all” rewrites rather than mess with undocumented hints, so I haven’t tried to work out exactly what the numbers mean.
Have you also seen examples the include this type of thing “OR_PREDICATES(6 18 43)” inside the use_concat() hint ?
Comment by Jonathan Lewis — January 3, 2014 @ 3:36 pm GMT Jan 3,2014 |
Jonathan,
Right I’ve single column indexes on a, b, and c
Yes I’ve seen such or_predicates with complex queries. For example USE_CONCAT(@”SEL$1″ 8 OR_PREDICATES(1 8 18)) there:
Comment by Franck Pachot — January 3, 2014 @ 4:01 pm GMT Jan 3,2014
This is the model
Nothing is noticeable when I changed the first predicate to (:b7 is null)
When I take out the first predicate from the query I got the following plan (in 10.2.0.4 and 11.2.0.3)
When I did a manual concatenation I got the following plan
Best regards
Comment by hourim — January 3, 2014 @ 12:02 pm GMT Jan 3,2014 |
Oracle has stopped using concatenation. I believe there is simple bug. Although conditions at line 2 and 6 are mutually exclusive, oracle counts the final cost as addition of COST for PLAN ID 3 COST for PLAN ID 7, instead of using maximal value. I have seen this in 11g before, but now we are upgrading for customer mission critical database on 12.1.0.2 and so it has passed through my hands again. As original system is Oracle 9.2, I can easily check there that oracle was smart enough in 9.2 to use concatenation without any help by hints / code rewrite.
Comment by Pavol Babel — February 20, 2016 @ 3:47 am GMT Feb 20,2016 |
[…] the most significant difference between concatenation and expansion – concatenation requires indexed access paths in all branches, or-expansion […]
Pingback by Conditional SQL – 5 | Oracle Scratchpad — March 2, 2018 @ 12:49 pm GMT Mar 2,2018 |