Что произойдет с вашим запросом, если вы запустите его с явным преобразованием вокруг аргумента (например, to_char (: 1) или to_number (: 1) в зависимости от ситуации)? Если это сделает ваш запрос быстрым, у вас есть ответ.
Однако, если ваш запрос все еще работает медленно с явным преобразованием, может быть другая проблема. Вы не упоминаете, какую версию Oracle вы используете, если в столбце высокой мощности (natural_key1) есть значения с очень искаженным распределением, вы можете использовать план запроса, сгенерированный при первом запуске запроса, который использовал неблагоприятное значение для: 1.
Например, если в вашей таблице из 1 миллиона строк было 400 000 строк с natural_key1 = 1234, а оставшиеся 600 000 были уникальными (или почти), оптимизатор не выбрал бы индекс, если ваш запрос ограничен natural_key1 = 1234. вы используете переменные связывания, если вы выполняете запрос впервые, оптимизатор выберет этот план для всех последующих запусков.
Один из способов проверить эту теорию состоит в том, чтобы запустить эту команду перед выполнением вашего теста:
alter system flush shared_pool;
Это удалит все планы запросов из мозга оптимизатора, поэтому следующий запуск оператора будет оптимизирован заново. В качестве альтернативы вы можете выполнить оператор как прямой SQL с литералами, без переменных связывания. Если в любом случае все прошло хорошо, вы бы знали, что ваша проблема связана с коррупцией в плане.
Если это так, вы не хотите использовать эту команду alter system в производственной среде - вы, скорее всего, ухудшите производительность вашей системы, если будете регулярно ее запускать, но вы можете обойти ее, используя динамический sql вместо переменных связывания или, если возможно заранее определить, что: 1 является неселективным, используйте несколько иной запрос для неселективных случаев (например, переупорядочение условий в предложении WHERE, что вызовет оптимизатор) использовать другой план).
Наконец, вы можете попробовать добавить подсказку индекса к вашему запросу, например ::
SELECT /*+ INDEX(src_table,<name of index for natural_key1>) */
unique_key
FROM src_table
WHERE natural_key1 = :1
AND natural_key2 = :2
AND natural_key3 = :3;
Я не большой поклонник индексных подсказок - это довольно хрупкий метод программирования. Если имя изменилось в индексе в будущем, вы никогда не узнаете его, пока ваш запрос не начнет работать плохо, плюс вы, возможно, застрелились, если в результате обновления сервера или изменений распределения данных оптимизатор сможет выбрать еще лучший план.