Search code examples
oracle-databaseoracle11gsql-execution-plansql-tuning

why does the optimizer choose the higher cost execution plan?


This is a re-occuring Problem for me. I have statements that work well for a while and after a while the optimizer decides to choose another execution plan. This even happens for when I query for exactly one (composite) primary key.

When I look up the execution plan in dba_hist_sql_plan, it shows me costs of 20 for the query using the primary key index and costs of 270 for the query doing a full table scan.

plan_hash_value Operation        Options              Cost  Search_Columns

2550672280  0   SELECT STATEMENT                       20
2550672280  1   PARTITION HASH   SINGLE                20
2550672280  2   TABLE ACCESS     BY LOCAL INDEX ROWID  20
2550672280  3   INDEX            RANGE SCAN            19                1

3908080950  0   SELECT STATEMENT                      270
3908080950  1   PARTITION HASH  SINGLE                270
3908080950  2   TABLE ACCESS    FULL                  270

I already noticed that the optimizer only uses the first column in the Primary key index and then does a range scan. But my real question is: Why does the optimizer choose the higher cost execution plan? It's not that both executions plans are used at the same time, I notice a switch within one snapshot and then it stays like that for several hours/days. So it can't be an issue of bind peeking.

Our current solution is that I call our DBA and he flushes the Statement Cache. But this is not really sustainable.

EDIT: The SQL looks something like this: select * from X where X.id1 = ? and X.id2 = ? and X.id3 = ? with (id1,id2,id3) being the composite primary key (with a unique index) on the table.


Solution

  • Apparently the optimizer doesn't correctly display costs regarding type conversions. The root cause for this Problem was incorrect type mapping for a date value. While the column in the database is of type DATE, the JDBC type was incorrectly java.sql.Timestamp. To compare a DATE column with a Timestamp search parameter, all values in the table need to be transferred to Timestamp first. Which is additional cost and renders an index unusable.