Let's say you have a table, called ORDERS, which contains ORDER_NUMBER, CUSTOMER_ID, and ORDER_DATE (among other fields). And you have one index on ORDER_NUMBER, another on CUSTOMER_ID, and third index on ORDER_DATE.
The following query is intended to select all orders that are older than the current order, from the same customer:
select ORDER_NUMBER from ORDERS
where CUSTOMER_ID = :BIND_VAIABLE_1
and ORDER_DATE <= :BIND_VARIABLE_2
and ORDER_NUMBER != :BIND_VARIABLE_3
In this case, :BIND_VARIABLE_2 would be a recent date, usually today's date, from a current order. The problem is, that Oracle seems to want to use the index on ORDER_DATE, which selects almost the entire table, then filters on CUSTOMER_ID, whereas it is much more efficient to use the index on CUSTOMER_ID instead (since there are only a few orders per customer).
The thing is, if you do a query without bind variables, it will always use CUSTOMER_ID like it should. But with bind variables, Oracle creates a query plan assuming that ORDER_DATE will be some random value, so ends up using the less efficient index.
How can I get Oracle to use the correct index in the presence of bind variables, without using index hints (since I can't modify the app)? I've already tried re-computing statistics, using histograms, etc. but without much luck. Ideally I'd like to turn off bind-variable optimization altogether, and have Oracle re-formulate a query plan based on the actual contents of the bind variables.
Edit: the purpose of this query is to find all previous orders by this particular customer, so BIND_VARIALBE_1 is the current customer, BIND_VARIABLE_2 would be the date of the current order, and BIND_VARIABLE_3 is the current order number.
DBMS_SQLDIAG.CREATE_SQL_PATCHwill do the job (blogs.oracle.com/optimizer/…) .CUSTOMER_ID = :BIND_VARIABLE_1andCUSTOMER_ID != :BIND_VARIABLE_3in the sameWHEREclause.:BIND_VARIABLE_1and:BIND_VARIABLE_3would either be the same (in which case no rows would be returned), or different (in which caseCUSTOMER_ID != :BIND_VARIABLE_3serves no purpose). Wondering if this might be what's forcing the use of theORDER_DATEindex.ORDER_DATEdefined as a DATE (or TIMESTAMP or similar date/time) type? Did some idiot use a mock value of31-DEC-2525to represent a nullORDER_DATE(but I would guess it is defined as NOT NULL). Is it defined asNOT NULL?