Sql – How could predicate pushing on an inline view slow down a query

optimizationoraclepredicatesqlsql-execution-plan

I have inherited a somewhat messy query that I am working on refactoring to be performant.

During this process, one of the things I did due to personal preference was change all of the ANSI-99 join syntax from the "inner join" and "left outer join" statements to be predicates in the query. I noticed two very strange things that I would appreciate an explanation on.

  1. Changing the joins from the "INNER JOIN…" syntax has changed the explain plan. With the ANSI 99 syntax, oracle did full table scans on the columns that were being joined. After changing the join syntax, it now does predicate pushing. Why would the join syntax change the explain plan?
  2. The predicate pushing on the inline view has actually slowed down the query by a very significant margin. The query that was running (prior to altering the joins) at around 3 sec. Now it is taking 9 sec. To be honest, I fairly new to reading explain plans so it's entirely possible that the restructuring of the query has slowed it down for a different reason. But ultimately my question is: "Is it possible for predicate pushing on indexed columns to slow down a query so substantially? If so, why?"

Thanks for the replies, and my apologies if this isn't very clear…

Best Solution

Is it possible for predicate pushing on indexed columns to slow down a query so substantially? If so, why?

Sure it is.

As a rule, predicate pushing makes the optimizer to choose NESTED LOOPS instead of HASH JOIN.

This can be slower if the condition is not selective.

This query

SELECT  *
FROM    table1, t1
        (
        SELECT  /*+ NO_PUSH_PRED */
                *
        FROM    table2 t2
        WHERE   t2.col1 = :value1
        ) t2o
WHERE   t2o.col2 = t1.col2

most probably will build a hash table over the contents of table1 and will probe the rows returned by the view against this hash table (or vice versa).

This query:

SELECT  *
FROM    table1, t1
        (
        SELECT  /*+ PUSH_PRED */
                *
        FROM    table2 t2
        WHERE   t2.col1 = :value1
        ) t2o
WHERE   t2o.col2 = t1.col2

will use the NESTED LOOPS and an index on (t2.col1, t2.col2) if it's defined.

The latter is more efficient if col2 is selective on table2, and less efficient if it's not.

My educated guess is that is exactly what's happening in your case.

If you post your queries and execution plans, I probably will be able to tell more.