У меня есть таблица, содержащая более 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 и т. Д.

4
Ali 11 Ноя 2009 в 08:33
Вы уверены, что проблема со временем связана с запросом, а не с драйвером, отправляющим данные на java?
 – 
mooreds
11 Ноя 2009 в 09:11

3 ответа

Лучший ответ

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

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

3
APC 11 Ноя 2009 в 15:19
+1 - Я видел это в прошлом с запросами Java к типам дат Oracle. Если у вас есть лицензия на использование пакета dbms_sqltune и запуск его с sql_id (общий пул или репозиторий AWR), вы увидите преобразование типа данных в результирующем анализе.
 – 
dpbradley
11 Ноя 2009 в 15:10
Привет, во-первых, спасибо всем. но то, что предложил APC, было моим предположением. Я использовал объект oracle.sql.DATE для установки значений переменных привязки, и он сработал ... запрос возвращен почти мгновенно, и когда я вернусь к java.sql.Timestamp, это та же проблема, что запрос идет на полное сканирование и занимает слишком много времени.
 – 
Ali
12 Ноя 2009 в 17:21
Но это усложняет мою работу, поскольку приложение является универсальным в том смысле, что оно может получать соединение, пары запросов для загрузки данных, где соединение может быть любой БД, например oracle, mysql и т. Д. Есть ли проблема в драйвере ojdbc, что он неправильно переводит тип объекта "Timestamp" для oracle? любые предложения о том, как исправить и сохранить независимость процесса от БД, будут оценены. Спасибо
 – 
Ali
12 Ноя 2009 в 17:21

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

Попробуйте это в 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. Поместите в оператор подсказку, чтобы указать, что он должен использовать нужный вам индекс.
2
APC 11 Ноя 2009 в 12:42
Нет -> Обычно нет. Может быть, он запускается только один раз в день с определенными значениями, и каждый день будет только один жесткий синтаксический анализ? Может быть, лучше жить с жестким синтаксическим анализом и позволить CBO предложить лучший план на основе запроса?
 – 
WW.
11 Ноя 2009 в 15:17
@WW: Если проблема все еще существует после того, как типы данных не были неявно преобразованы - см. Мои ответы и APC. Я никогда не видел такой проблемы, связанной только с привязкой переменных.
 – 
OMG Ponies
11 Ноя 2009 в 20:30
Слишком много сказать для комментария, но посмотрите это: asktom.oracle.com/pls/asktom/…
 – 
WW.
12 Ноя 2009 в 00:46
Привет, я проверил план выполнения для переменных привязки, которые он использовал index. Но здесь я предполагаю, что проблема заключалась в том, что объект, переданный в java для переменной связывания, не был обработан / преобразован должным образом в значение типа «Дата» для Oracle DB, поэтому он не использовал индекс. см. мой ответ APC
 – 
Ali
12 Ноя 2009 в 17:30

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

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

0
Alan 11 Ноя 2009 в 08:50
Неправильный синтаксис: / * + INDEX (индекс таблицы) * / или еще лучше использовать новое предложение спецификации индекса с / * + INDEX (table (column)) * / или / * + INDEX (table (table.column)) * /
 – 
David Aldridge
11 Ноя 2009 в 12:49