2012-08-09 4 views
0

Я написал скалярную функцию (DYNAMIC_DATE), которая преобразует текстовое значение в дату/время. Например, DYANMIC_DATE('T-1') (T-1 = сегодня минус 1 = «вчера») возвращает 08-AUG-2012 00:00:00. Он также принимает строки даты: DYNAMIC_DATE('10/10/1974').Скалярная функция Oracle в выражении WHERE приводит к плохой работе

Функция использует операторы CASE для анализа единственного параметра и расчета даты относительно sysdate.

Хотя это не делает использование любой таблицы в своей схеме, он делает использование TABLE типа для хранения строк даты формата:

TYPE VARCHAR_TABLE IS TABLE OF VARCHAR2(10); 
formats VARCHAR_TABLE := VARCHAR_TABLE ('mm/dd/rrrr','mm-dd-rrrr','rrrr/mm/dd','rrrr-mm-dd'); 

Когда я использую функцию в предложении SELECT, то запрос возвращает в < 1 секунду:

SELECT DYNAMIC_DATE('MB-1') START_DATE, DYNAMIC_DATE('ME-1') END_DATE 
FROM DUAL 

Если я использую его против нашей даты таблицы измерения (91311 всего записей), запрос завершается в < 1 второе:

SELECT count(1) 
from date_dimension 
where calendar_dt between DYNAMIC_DATE('MB-1') and DYNAMIC_DATE('ME-1') 

Другие, однако, возникают проблемы с функцией, если она используется против большой таблицы (26,301,317 записи):

/* 
cost: 148,840 
records: 151,885 
time: ~20 minutes 
*/ 
SELECT count(1) 
FROM ORDERS ord 
WHERE trunc(ord.ordering_date) between DYNAMIC_DATE('mb-1') and DYNAMIC_DATE('me-1') 

Однако, тот же запрос, используя «жестко закодированные» даты, возвращает довольно быстро: установка ванильного

/* 
cost: 144,257 
records: 151,885 
time: 62 seconds 
*/ 
SELECT count(1) 
FROM ORDERS ord 
WHERE trunc(ord.ordering_date) between to_date('01-JUL-2012','dd-mon-yyyy') AND to_date('31-JUL-2012','dd-mon-yyyy') 

поставщика не включает в себя индекс на ORDERING_DATE поля.

объяснить планы обоих запросов аналогичны:

с функцией: using function

с жестко закодированными датами: hard-coded dates

  • ли функция DYNAMIC_DATE вызывается несколько раз в WHERE статья?
  • Что еще может объяснить несоответствие?

** редактировать **

NONUNIQUE индекс был добавлен в таблицу Orders. Оба запроса выполняются в < 1 секунда. Оба плана одинаковы (подход), но тот, у кого функция, является более низкой стоимостью.

Я удалил из функции ключевое слово DETERMINISTIC; запрос выполнен в < 1 секунда.

  • Действительно ли проблема с функцией или она связана с таблицей?
  • Через 3 года, когда эта таблица еще больше, и если я не включу ключевое слово DETERMINISTIC, будет ли запрос пострадать?
  • Будет ли ключевое слово DETERMINISTIC повлиять на результаты функции? Если завтра я запустил DYNAMIC_DATE('T-1'), получаю ли я такие же результаты, как если бы я запускал его сегодня (08/09/2012)? Если это так, этот подход не будет работать.
+0

Если планы объяснения схожи, значит ли это, что они не идентичны? Если они не идентичны, можете ли вы опубликовать два плана? –

+0

Планы - это то же самое (что означает шаги); только общая стоимость отличается. – craig

+0

Сколько записей в «ORDERS»? – Ollie

ответ

1

Если этапы плана идентичны, то общая сумма выполняемой работы должна быть одинаковой. Если вы трассируете сеанс (что-то простое, например, set autotrace on в SQL * Plus или что-то более сложное, например, трассировка события 10046), или если вы посмотрите на DBA_HIST_SQLSTAT при условии, что у вас есть лицензионный доступ к таблицам AWR, вы видите (примерно) ту же сумму логического ввода-вывода и потребления ЦП для двух запросов? Возможно ли, что разница во времени выполнения, который вы видите, является результатом кэширования данных при выполнении второго запроса?

+0

В моем тестировании я обычно выполняю запрос с помощью функции после жесткого кодирования. Разве это не устранит преимущества кеширования? – craig

+0

@craig - Вы можете запросить таблицы AWR? Если да, то где «DBA_HIST_SQLSTAT» показывает, что истекшая разность времени между запросами? Является ли разница все из-за прошедшего времени PL/SQL? Объявлена ​​ли ваша функция 'DETERMINISTIC'? –

+0

Не объявлено 'DETERMINISTIC'. Что это значит, точно? У меня есть доступ к таблице «DBA_HIST_SQLSTAT». Вы можете порекомендовать запрос? – craig

1

Я предполагаю, что проблема не в вашей функции. Попробуйте создать индекс на основе функции на trunc(ord.ordering_date) и посмотреть планы объяснений.

CREATE INDEX ord_date_index ON ord(trunc(ord.ordering_date)); 
+0

Если это имеет значение, я пробовал два запроса без логики TRUNC(). Результаты (т. Е. Производительность) схожи. Это изменяет ваше мышление? – craig

+1

Затем я хотел бы увидеть функцию 'DYNAMIC_DATE' и посмотреть, что происходит там. – Annjawn

Смежные вопросы