2010-12-02 2 views
0

У меня есть запрос, который принимать данные от 5 огромного стола, не могли бы вы мне помочь с настройкой производительности этого запроса:Помощи для настройки SQL - ORACLE

SELECT DECODE(SIGN((t1.amount - NVL(t2.amount, 0)) - 4.999), 1, NVL(t2.amount, 0), t1.amount) AS amount_1, 
     t1.element_id, 
     t1.start_date , 
     t1.amount, 
     NVL(t5.abrev, NULL) AS criteria, 
     t1.case_id , 
     NVL(t5.value, NULL) segment, 
     add_months(t1.start_date, -1) invoice_date, 
     NVL((SELECT SUM(b.amount) 
      FROM TABLE1 a, TABLE3 b 
      WHERE a.element_id = b.element_id 
       AND b.date_invoicing < a.start_date 
       AND t1.element_id = a.element_id), 
      0) amount_2 
    FROM TABLE1 t1, TABLE2 t2, TABLE3 t3, TABLE4 t4, TABLE5 t5 
WHERE t1.TYPE = 'INVOICE' 
    AND t2.case_id = t3.case_id 
    AND t2.invoicing_id = t3.invoicing_id 
    AND t2.date_unpaid IS NULL 
    AND t1.element_id = t3.element_id(+) 
    AND add_months(t1.start_date, -1) < 
     NVL(t4.DT_FIN_DT(+), SYSDATE) 
    AND add_months(t1.start_date, -1) >= t4.date_creation(+) 
    AND t1.case_id = t4.case_id(+) 
    AND t4.segment = t5.abrev(+) 
    AND t5.Type(+) = 'CRITERIA_TYPE'; 

там что-то не так, и можно был бы заменить чем-то еще?
Спасибо за вашу помощь

+2

Как бы то ни было, у вас есть попытка внешнего соединения с t3 с помощью (+), которые принудительно возвращаются во внутреннее соединение другими предикатами, которые не используют (+), например, «t2.case_id = t3.case_id». Если вы могли бы написать это с помощью ANSI-соединений, это было бы менее подверженным ошибкам и более простым для чтения. Тем не менее это не имеет никакого отношения к производительности. – 2010-12-02 14:16:25

ответ

1

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

... Но некоторые вещи, которые я бы иметь дело с:

  1. Наружный присоединиться к Table3 в основном запросе не является полным, как @TonyAndrews отметил в своем комментарии выше. См. Пример «Неполный пример соединения» на странице Common errors seen when using OUTER-JOIN. Это означает, что ваш запрос, вероятно, приводит к неправильным результатам, но, не зная полного намерения запроса и схемы, никто, но вы точно это знаете.

    Обновление вашего запроса для использования синтаксиса ANSI в стиле INNER/[LEFT|RIGHT] OUTER из Oracle TableName.ColumnName(+) поможет сделать это более очевидным.

  2. Скалярный подзапрос будет запускаться для каждой строки и может быть медленным (при условии, что TABLE3 большой). Это будет очень медленным, если не полезный индекс TABLE3.element_id и TABLE3.date_invoicing:

    NVL((SELECT SUM(b.amount) 
        FROM TABLE1 a, TABLE3 b 
        WHERE a.element_id = b.element_id 
         AND b.date_invoicing < a.start_date 
         AND t1.element_id = a.element_id), 
        0) amount_2 
    

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

    NVL((SELECT SUM(b.amount) 
        FROM TABLE3 b 
        WHERE t1.element_id = b.element_id 
         AND b.date_invoicing < t1.start_date, 
        0) amount_2 
    

    Или, вы можете быть даже лучше рефакторинга это использовать аналитическую функцию (SO question, Oracle documentation), если критерии для суммирования b.amount значений является то же самое, что и для включения их в запросе, в первую очередь:

    SUM(b.amount) OVER (PARTITION BY b.element_id) amount_2 
    

    Очевидно, у вас в настоящее время есть разные критерии для суммирования b.amount, так как вы присоединяетесь к TABLE3 по-разному в основном запросе и в подзапросе, но я бы предположил, что это скорее фактор «Незавершенного объединения трейла», чем целенаправленный дизайн (догадка о моей части , поскольку я не могу сказать цель запроса из самого кода).

2

Первое, что вы должны сделать, это использовать Явные Соединения. Это отделит ваши соединения от ваших фильтров и поможет вам настроить это лучше.

Проверьте правильность этих соединений.

SELECT 
    DECODE(SIGN((t1.amount - NVL(t2.amount, 0)) - 4.999), 1, NVL(t2.amount, 0), t1.amount) AS amount_1, 
    t1.element_id, 
    t1.start_date , 
    t1.amount, 
    NVL(t5.abrev, NULL) AS criteria, 
    t1.case_id , 
    NVL(t5.value, NULL) segment, 
    add_months(t1.start_date, -1) invoice_date, 
    NVL 
    (
     (SELECT SUM(b.amount) 
     FROM TABLE1 a, TABLE3 b 
     WHERE a.element_id = b.element_id 
     AND b.date_invoicing < a.start_date 
     AND t1.element_id = a.element_id), 
    0) amount_2 
FROM 
    TABLE1 t1 

    LEFT OUTER JOIN TABLE3 t3 
     on t1.element_id = t3.element_id 

    INNER JOIN TABLE2 t2, 
     on t2.invoicing_id = t3.invoicing_id 
     and t2.case_id = t3.case_id 

    LEFT OUTER JOIN TABLE4 t4 
     on t1.case_id = t4.case_id 

    LEFT OUTER JOIN TABLE5 t5 
     on t4.segment = t5.abrev 

WHERE t1.TYPE = 'INVOICE' 
    AND t2.date_unpaid IS NULL 
    AND add_months(t1.start_date, -1) < NVL(t4.DT_FIN_DT(+), SYSDATE) 
    AND add_months(t1.start_date, -1) >= t4.date_creation(+) 
    AND t5.Type(+) = 'CRITERIA_TYPE'; 

Если они есть, то вы можете сделать несколько вещей, но лучше всего посмотреть на план выполнения.

+0

Повышает ли производительность или читаемость? – mcha 2010-12-02 14:14:50

+2

С точки зрения производительности, они должны быть точно такими же. Разделение помогает вам идентифицировать вещи, чтобы настроиться намного лучше. – 2010-12-02 14:22:27

1

Возможно, оптимизатор подготовил субоптимальный план выполнения. Или это может быть очень быстро запущено как можно быстрее, учитывая объем работы, который фактически должна делать база данных. Без объяснения плана, зная ключи, отношения и индексы, немного сложно сказать, что происходит.

Скалярные подзапросы в списке выбора обычно Не рекомендуется, когда внешний запрос возвращает большое количество строк.

Следующие выражения могут помешать оптимизатору использовать статистику из-за вызовов функций. Индексы, вероятно, не будут использоваться по той же причине.

AND add_months(t1.start_date, -1) < NVL(t4.DT_FIN_DT(+), SYSDATE) 
AND add_months(t1.start_date, -1) >= t4.date_creation(+) 

не может действительно быть более точным, чем :)

1

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

0

Это ABIT странно здесь, когда вы гнездятся Выберите заявление в другой

NVL((SELECT SUM(b.amount) 
      FROM TABLE1 a, TABLE3 b 
      WHERE a.element_id = b.element_id 
       AND b.date_invoicing < a.start_date 
       AND t1.element_id = a.element_id), 
      0) amount_2 

вам нужно написать еще раз в виде таблицы и присоединиться после «С».

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