Индекс по столбцу типа даты в Oracle не используется, когда запрос запускается из Java - PullRequest
4 голосов
/ 11 ноября 2009

У меня есть таблица, содержащая более 15 миллионов записей в Oracle. это своего рода таблица журнала, в которой есть столбец create_ts типа «дата». у меня есть простой «неуникальный» индекс типа на колонке созданных_ц.

У меня есть простой запрос диапазона:

select * from table1 where created_ts >= ? and created_ts <= ?; 

когда я запускаю этот запрос из SQLPlus или SQL Developer и т. Д., Например:

select * from table1 
where created_ts >= TO_DATE( '2009-11-10 00:00:00', 'YYYY-MM-DD HH24:MI:SS') 
and created_ts <= TO_DATE( '2009-11-10 23:59:59', 'YYYY-MM-DD HH24:MI:SS'); 

запрос возвращается в течение 1-2 секунд макс.

но когда я запускаю точно такой же запрос в java через JDBC и устанавливаю соответствующий "?" params используя объект java.sql.Timestamp. запрос занимает много времени. Анализируя процесс оракула, он идет на полное сканирование таблицы и не использует индекс.

драйвер jdbc, который я использую, ojdbc5 11.1.0.7.0

Может кто-нибудь, пожалуйста, помогите .. как правильно создать индекс, чтобы он использовал индекс.


Моя проблема была решена, когда я использовал объекты «oracle.sql.DATE» для установки переменных связывания вместо «java.sql.timestamp». Запрос использовал индекс и выполнялся практически в течение 1-2 секунд.

Спасибо всем, кто ответил и помог.

Но это проблематично для меня, так как это решение зависит от БД, и мое приложение получает соединение с БД и запросы в качестве параметров, а также загружает и обрабатывает данные в общем виде. Соединение с БД может быть любой СУБД, такой как oracle, mysql и т. Д.

Ответы [ 3 ]

3 голосов
/ 11 ноября 2009

Это классическое поведение для неявного преобразования типов данных. Поскольку база данных должна преобразовывать тип данных столбца, она не может использовать индекс для этого столбца.

В вашем случае я подозреваю, что это связано с использованием вами java.sql.Timestamp. Можно ли будет использовать эквивалентный тип из пакета типов данных Oracle , oracle.sql.Timestamp? Очевидно, что это может иметь некоторые побочные эффекты, но я думаю, что вы должны по крайней мере проверить это, чтобы увидеть, решает ли это вашу проблему.

2 голосов
/ 11 ноября 2009

Разница может быть связана с переменными связывания и литеральными значениями. Вы не сравниваете одни и те же вещи.

Попробуйте это в SQL * Plus: -

explain plan for
select * from table1 where created_ts >= :1 and created_ts <= :2;

set markup html preformat on
set linesize 100
set pagesize 0  
select plan_table_output 
from table(dbms_xplan.display('plan_table',null,'serial'));

Это покажет вам план, который Oracle выберет при использовании переменных связывания. В этом случае Oracle должен составить план, прежде чем вы предоставите значения для своего диапазона дат. Он не знает, выбираете ли вы только небольшую часть данных или все из них. Если у вас тот же план (полное сканирование?), Что и у вашего плана из Java, по крайней мере, вы знаете, что происходит.

Тогда вы могли бы рассмотреть: -

  1. Включение просмотра привязки (но только после тестирования это не приводит к ухудшению работы)
  2. Тщательная привязка литеральных значений из Java таким образом, чтобы не допустить SQL-инъекцию
  3. Помещение подсказки в утверждение, указывающее, что оно должно использовать индекс, к которому вы хотите.
0 голосов
/ 11 ноября 2009

Вы должны попробовать подсказку в форме / * + USE_INDEX (имя_таблицы, имя_индекса) * /

Я предполагаю, что оптимизатор выбирает полное сканирование таблицы, потому что он считает это лучшим вариантом при отсутствии знания значений связывания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...