Как оптимизировать запрос Oracle, который имеет to_char в предложении where для даты - PullRequest
4 голосов
/ 10 апреля 2010

У меня есть таблица, которая содержит около 49403459 записей.

Я хочу запросить таблицу в диапазоне дат. скажем 04/10/2010 до 04/10/2010. Однако даты хранятся в таблице в формате 10-APR-10 10.15.06.000000 AM (отметка времени).

В результате, когда я делаю

SELECT bunch,of,stuff,create_date
FROM myTable
WHERE TO_CHAR (create_date,'MM/DD/YYYY)' >= '04/10/2010'
AND TO_CHAR (create_date, 'MM/DD/YYYY' <= '04/10/2010'

Я получаю 529 строк, но за 255.59 секунд! Это потому, что, я думаю, я делаю TO_CHAR на КАЖДОЙ записи.

Однако, когда я делаю

SELECT bunch,of,stuff,create_date
FROM myTable
WHERE create_date >= to_date('04/10/2010','MM/DD/YYYY')
AND create_date <= to_date('04/10/2010','MM/DD/YYYY')

тогда я получу 0 результатов за 0.14 секунд.

Как мне сделать этот запрос быстрым и при этом получить действительные (529) результаты?

На данный момент я не могу изменить индексы. Сейчас я думаю, что индекс создается для столбца create_date.

Как можно преобразовать два диапазона дат, чтобы первый диапазон дат преобразовывался в метку времени со всеми 0, а второй - в метку времени, которая является последней меткой времени даты. Если это имеет смысл ...?

Следующее условие where также не приводит ни к каким результатам:

WHERE            
create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')
AND
create_date <= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')

Ответы [ 6 ]

4 голосов
/ 11 апреля 2010

Я получаю 529 строк, но через 255,59 секунд! Это потому, что я думаю, что я делаю TO_CHAR в КАЖДОЙ записи.

Если бы вы сгенерировали план выполнения для вашего первого запроса ...

explain plan for 
SELECT bunch,of,stuff,create_date
FROM myTable
WHERE TO_CHAR (create_date,'MM/DD/YYYY)' >= '04/10/2010'
AND TO_CHAR (create_date, 'MM/DD/YYYY') <= '04/10/2010'
/

... вы увидите, что он выполняет полное сканирование таблицы. Это потому, что to_char() предотвращает использование вашего индекса на CREATE DATE.

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

SELECT bunch,of,stuff,create_date
FROM myTable
WHERE             
create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 
AND 
create_date <= to_timestamp('04/10/2010 23:59:59:123000','MM/DD/YYYY HH24:MI:SS.FF')
/

... но я ожидаю, что это было ближе к 0,14 секунды, чем к 4 минутам.

3 голосов
/ 11 апреля 2010

Конечно, это не работает:

WHERE            
    create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')
AND
    create_date <= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')

Потому что это вернуло бы только те строки, где create_date 4/10/2010 12:00 AM точно !

Если вы хотите получить все строки, в которых происходит create_date, в любое время дня 4/10/2010, используйте это:

WHERE            
    create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')
AND
    create_date < to_timestamp('04/11/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')

ИЛИ, если вы предпочитаете:

WHERE create_date BETWEEN to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF')
                      AND to_timestamp('04/10/2010 23:59:59.999999','MM/DD/YYYY HH24:MI:SS.FF')

Кстати, когда вы хотите представлять полночь, вы можете опустить все остальные части. Так что вы могли бы просто сказать:

WHERE            
    create_date >= to_timestamp('04/10/2010','MM/DD/YYYY')
AND
    create_date < to_timestamp('04/11/2010','MM/DD/YYYY')
2 голосов
/ 10 апреля 2010

Это работает:

WHERE             
create_date >= to_timestamp('04/10/2010 00:00:00.000000','MM/DD/YYYY HH24:MI:SS.FF') 
AND 
create_date <= to_timestamp('04/10/2010 23:59:59:123000','MM/DD/YYYY HH24:MI:SS.FF') 
2 голосов
/ 10 апреля 2010

В вашем первом запросе вы выполняете сравнение символов, а не сравнение дат, которое не должно давать правильных результатов.

Например, используя вашу логику, 01/02/2009 будет больше, чем 01/01/2010, потому что дневной компонент '02' больше, чем дневной компонент '01' при сравнении символов, и год никогда не будет оцениваться .

1 голос
/ 10 апреля 2010
SELECT bunch,of,stuff,create_date
  FROM myTable
 WHERE create_date >= to_date('04/10/2010','MM/DD/YYYY')
   AND create_date < to_date('04/11/2010','MM/DD/YYYY')

Дата 10.04.2010 включает в себя все значения даты с полуночи 10-го до 23:59:59, поэтому получение всего, что меньше 11-го, будет охватывать все базы. Альтернатива заключается в том, чтобы данные в myTable усекались при вводе данных в поле CREATE_DATE; Я предпочитаю делать это для полей DATE, и если я забочусь о компонентах времени, я использую TIMESTAMPs.

0 голосов
/ 21 мая 2010

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

ГДЕ create_date> = TRUNC (to_date ('04 / 10/2010 ',' MM / DD / YYYY '))

или добавьте hh: mi: ss к предикату. Это не работает просто потому, что вы форматируете дату не так, как ожидает Oracle.

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