У меня есть таблица, содержащая более 15 миллионов записей в Oracle. своего рода таблица журнала, в которой есть столбец created_ts типа «дата». У меня есть простой "неуникальный" индекс типа в столбце created_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 ответа
Это классическое поведение для неявного преобразования типа данных. Поскольку базе данных необходимо преобразовать тип данных столбца, она не может использовать какой-либо индекс для этого столбца.
Я подозреваю, что в вашем случае это связано с использованием вами java.sql.Timestamp
. Можно ли использовать эквивалентный тип из пакет типов данных Oracle, oracle.sql.Timestamp
? Очевидно, это может иметь некоторые побочные эффекты, но я думаю, вам следует хотя бы проверить это, чтобы увидеть, решит ли это вашу проблему.
Разница может быть связана с привязкой переменных к буквальным значениям. Вы не сравниваете одно и то же.
Попробуйте это в 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, по крайней мере, вы знаете, что происходит.
Тогда вы могли бы подумать: -
- Включение просмотра привязки (но только после тестирования это не приведет к ухудшению чего-либо еще)
- Тщательная привязка буквальных значений из java таким образом, чтобы не допускать SQL-инъекций
- Поместите в оператор подсказку, чтобы указать, что он должен использовать нужный вам индекс.
Вам следует попробовать подсказку в форме / * + USE_INDEX (имя_таблицы, имя_индекса) * /
Я предполагаю, что оптимизатор выбирает полное сканирование таблицы, потому что он видит это как лучший вариант при отсутствии знания значений привязки.
Похожие вопросы
Новые вопросы
java
Java - это язык программирования высокого уровня. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег редко используется отдельно и чаще всего используется вместе с [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] и [maven].