Медленный запрос при использовании функции datediff в Oracle - PullRequest
0 голосов
/ 30 сентября 2019

В качестве заголовка у меня есть следующий код:

 SELECT
        *
    FROM
        de.Department
    WHERE
        de.flag = 1
        AND   de.DepartmentNum IN (10,4)
        AND   de.status IN (0,-1,100)
        AND   datediff('dd',de.datequit,'30-SEP-19') > 9

Функция datediff делает мой запрос очень медленным (16 секунд для 11 записей), а также очень высокой стоимостью (~ 43k).

Вот мой код функции datediff

create or replace FUNCTION       DATEDIFF 
(
  P_TYPE_DATE IN VARCHAR2 
, P_START_DATE IN TIMESTAMP 
, P_END_DATE IN TIMESTAMP 
) RETURN NUMBER AS 
  v_Result NUMBER := -1;
BEGIN

  IF P_TYPE_DATE IS NOT NULL AND P_START_DATE IS NOT NULL AND P_END_DATE IS NOT NULL THEN
    CASE UPPER(P_TYPE_DATE) 
        WHEN 'DD' THEN RETURN ROUND(TRUNC(P_END_DATE,'DD') - TRUNC(P_START_DATE,'DD'),0);
        WHEN 'HH' THEN RETURN ROUND((TRUNC(P_END_DATE,'HH') - TRUNC(P_START_DATE,'HH')) * 24,0);
        WHEN 'MI' THEN RETURN ROUND((TRUNC(P_END_DATE,'MI') - TRUNC(P_START_DATE,'MI')) * 24 * 60,0);
        WHEN 'SS' THEN RETURN ROUND((TRUNC(P_END_DATE,'MI') - TRUNC(P_START_DATE,'MI')) * 24 * 60 * 60 + extract(second from (P_END_DATE - P_START_DATE)),0);
        ELSE RETURN NULL;
    END CASE;
  END IF;
  RETURN NULL;
  EXCEPTION
    WHEN OTHERS THEN
       raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END DATEDIFF;

Я использовал SELECT *, потому что я хочу получить почти столбец в таблице Department, поэтому он больше не изменится, если я выберу нужные мне столбцы.

Могу ли я переписать, чтобы улучшить производительность и стоимость?

Майни, спасибо!

1 Ответ

4 голосов
/ 30 сентября 2019

Я создал функцию с именем datediff в качестве функции datediff в SQL, сэр

Не используйте пользовательские функции, поскольку они не позволяют Oracle использовать индекс для столбца;вместо этого просто сравните столбец со статическими значениями:

SELECT *
FROM   Department
WHERE  flag = 1
AND    DepartmentNum IN (10,4)
AND    status IN (0,-1,100)
AND    datequit > DATE '2019-09-30' + INTERVAL '9' DAY

или

AND    datequit > DATE '2019-09-30' + NUMTODSINTERVAL( 9, 'DAY' )

или

AND    datequit > DATE '2019-09-30' + 9

Вот мой код функции datediff

...
WHEN 'DD' THEN RETURN ROUND(TRUNC(P_END_DATE,'DD') - TRUNC(P_START_DATE,'DD'),0);
...

Если вы хотите сделать эквивалентное сравнение с использованием TRUNC, чтобы игнорировать временные компоненты, тогда перейдите от использования сравнения «больше чем» к использованию «больше или равно» и добавьте единицу. единица времени (день в вашем примере) с ожидаемой разницей. Например:

SELECT *
FROM   Department
WHERE  flag = 1
AND    DepartmentNum IN (10,4)
AND    status IN (0,-1,100)
AND    datequit >= DATE '2019-09-30' + INTERVAL '10' DAY
...