views:

465

answers:

1

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

+2  A: 

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.

Quassnoi
Thanks for the explanation. Is it common that simply changing the syntax of the join would would change if predicate pushing is being used or not?
jnt30
@jnt30: Oracle's optimizer can work in inpredictable ways. I personally OUTLINE every query that is going to run for more than 10 seconds in worst case.
Quassnoi
@Quassnoi: Ok, thanks. I know I saw a few other of your posts regarding this, I'll take a look at those and try to figure it all out. I've primarily been a Java developer, so some of this is very new to me. I appreciate the time you took to answer my question.
jnt30