I have a pretty simple select statement,
select column 4 from table_x where column1=:1 and column2=:2 and column3=:3
Columns 1,2 and 3 make up the primary key on the table.
For some reason, rather then using the primary key index, oracle is using a nonclustered index that only contains 1 of the columns.
The only thing that I can find for why the optimizer is ignoring the primary key index, is that the bind variables used in the query are not defined the same way as the columns. The bind variables are all defined as varchar(32), the columns are nchar, number, and nchar. Is this mismatch enough to prevent the optimizer from using the primary key index?
Stats have been updated on the table and all the indexes.
Best Answer
It isn't like there is a rule for the optimizer choosing the index with the very same columns that the query predicates have.
You should always use your bind variables with the proper type. No, in this specific case, those types do not prevent the optimizer from using your index.
Below is just an artificially constructed example. I do not know your table/index structure and data distribution.
With the above sample data, we have 1 million rows, with
C1
having the same value everywhere,C2
having 1000 uniformly distributed different values andC3
being unique (with no constraint on it).Notice in
Peeked Binds
section the type of the variables (VARCHAR2
), and in thePredicate Information
section how they were automatically converted with theSYS_OP_C2C
andTO_NUMBER
functions. This implicit conversion in this case does not prevent index usage, but you will not be so lucky with other implicit conversions. (Also notice how I got 0 row as result, while I should have got 1 row as result with those values - but that is a different topic.)The optimizer chose the index on column C3 instead of the PK index. The cost of the query is 4. So the cost of the PK index should be higher. Let's see with a hint:
The usage of PK index is possible, but still, the optimizer did not choose it. Now most people would say their cost is the same (4), but they would be wrong. Such execution plans do not show all the details. We can check those from our plan table (or
V$SQL_PLAN
). I have already placed the plan of the PK index version there with the aboveEXPLAIN PLAN
statement, now do it for the original as well:We have both plans in the plan table. The important factor not being displayed is the CPU cost:
Notice how the
COST
equals toIO_COST
. However, theCPU COST
of using the PK index is higher than of the single column index. Simply put, even if the IO cost is the same, processing more columns requires more CPU time.Also it is a logical decision, because in this example
C3
alone is already unique, so using a smaller index with fewer columns, even if not significantly, should be faster.When in doubt, with so simple statements and low query cost, you should inspect the details as well. If you have a similarly very selective column, this could be the reason for the optimizer choosing the index on it.