Помощь по настройке SQL - ORACLE - PullRequest
0 голосов
/ 02 декабря 2010

У меня есть запрос, который берет данные из 5 огромных таблиц. Не могли бы вы помочь мне с настройкой производительности этого запроса:

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';

что-то не так и может быть заменено чем-то другим?* Спасибо за вашу помощь

Ответы [ 5 ]

2 голосов
/ 02 декабря 2010

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

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

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';

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

1 голос
/ 02 декабря 2010

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

Но ... некоторые вещи, которые меня интересуют:

  1. Внешнее соединение с TABLE3 в основном запросе не завершено, как @TonyAndrews упомянул в своем комментарии выше.См. Пример «Incomplete Join Trail» на Распространенные ошибки при использовании OUTER-JOIN . Это означает, что ваш запрос, вероятно, дает неправильные результаты , но, не зная полного намерения запроса и схемы, никто, кроме вас, не может знать это наверняка.

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

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

    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 вопрос , Документация Oracle ), если критерии суммирования значений b.amount совпадают с критериями для включения их в запрос в первую очередь:

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

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

1 голос
/ 02 декабря 2010

Вам необходимо узнать, как просматривать и понимать планы выполнения. Этот предыдущий вопрос - хорошее место для начала.

1 голос
/ 02 декабря 2010

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

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

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

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

Не может быть более конкретным, чем это:)

0 голосов
/ 18 июля 2017

Это немного странно, когда вы вкладываете оператор Select внутри другого

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

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

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