Skip to Main Content

SQL & PL/SQL

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Why a table full scan when I've got the PK in the WHERE clause?

586609Dec 4 2009 — edited Dec 7 2009
There is a very complex query that I need to optimize in an Oracle 10gR2 environment. I am deconstructing it into layers to see what is causing the first bottleneck. The innermost portion is fine, with an explain plan cost of 54. With a typical value for the bind variable, it returns 125 zero_id values. There are over 100,000 rows in table T_ONE in my test database, but my customer has over one million rows in their production instance.
              WITH t_merged_id AS (SELECT DISTINCT zero_id FROM t_zero WHERE NVL(column2, zero_id) = :i_id)
              SELECT   t_one.one_id
                  FROM t_one
                      INNER JOIN t_two
                          ON t_one.column1 = t_two.two_id
                      INNER JOIN t_merged_id
                          ON t_two.column10 = t_merged_id.zero_id
              UNION ALL
              SELECT   t_one.one_id
                  FROM t_one
                      INNER JOIN t_two
                          ON t_one.column2 = t_two.two_id
                      INNER JOIN t_merged_id
                          ON t_two.column10 = t_merged_id.zero_id
              UNION ALL
              SELECT   t_one.one_id
                  FROM t_one
                      INNER JOIN t_three
                          ON t_one.column3 = t_three.three_id
                      INNER JOIN t_merged_id
                          ON t_three.column10 = t_merged_id.zero_id
              UNION ALL
              SELECT   t_one.one_id
                  FROM t_one
                      INNER JOIN t_four
                          ON t_one.column4 = t_four.four_id
                      INNER JOIN t_two
                          ON t_four.column1 = t_two.two_id
                      INNER JOIN t_merged_id
                          ON t_two.two_id = t_merged_id.zero_id
              UNION ALL
              SELECT   t_one.one_id
                  FROM t_one INNER JOIN t_merged_id ON t_one.column5 = t_merged_id.zero_id
              UNION
              SELECT   t_one.one_id
                  FROM t_one INNER JOIN t_merged_id ON t_one.column6 = t_merged_id.zero_id
However, the next step is to obtain a bunch of columns from T_ONE for each of those ONE_ID values. Adding that looks like the following, which causes a table full scan on T_ONE (and an explain plan cost over 1,500 for this query in my test system) and it takes far too long to return the results.
SELECT   t_one.*
    FROM     t_one
         INNER JOIN
             (--This is the start of the query shown above
              WITH t_merged_id AS (SELECT DISTINCT zero_id FROM t_zero WHERE NVL(column2, zero_id) = :i_id)
              SELECT   t_one.one_id
                  FROM t_one
                      INNER JOIN t_two
                          ON t_one.column1 = t_two.two_id
                      INNER JOIN t_merged_id
                          ON t_two.column10 = t_merged_id.zero_id
              UNION ALL
              SELECT   t_one.one_id
                  FROM t_one
                      INNER JOIN t_two
                          ON t_one.column2 = t_two.two_id
                      INNER JOIN t_merged_id
                          ON t_two.column10 = t_merged_id.zero_id
              UNION ALL
              SELECT   t_one.one_id
                  FROM t_one
                      INNER JOIN t_three
                          ON t_one.column3 = t_three.three_id
                      INNER JOIN t_merged_id
                          ON t_three.column10 = t_merged_id.zero_id
              UNION ALL
              SELECT   t_one.one_id
                  FROM t_one
                      INNER JOIN t_four
                          ON t_one.column4 = t_four.four_id
                      INNER JOIN t_two
                          ON t_four.column1 = t_two.two_id
                      INNER JOIN t_merged_id
                          ON t_two.two_id = t_merged_id.zero_id
              UNION ALL
              SELECT   t_one.one_id
                  FROM t_one INNER JOIN t_merged_id ON t_one.column5 = t_merged_id.zero_id
              UNION
              SELECT   t_one.one_id
                  FROM t_one INNER JOIN t_merged_id ON t_one.column6 = t_merged_id.zero_id
               --This is the end of the query shown above
               ) t_list
         ON t_one.one_id = t_list.one_id
My question is, why wouldn’t Oracle use the existing index PK_T_ONE, which is keyed on T_ONE.ONE_ID? I tried refactoring the query using a “WHERE t_one.one_id IN” construct instead of the INNER JOIN but it didn’t make any difference. Neither did adding an index hint, which I hoped would force the use of the PK index.

Any ideas?
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Jan 4 2010
Added on Dec 4 2009
12 comments
2,050 views