Как я могу исключить CROSS JOIN в большом запросе, который производит условные суммы? - PullRequest
0 голосов
/ 17 апреля 2020

У меня есть запрос, который производит 529 032 строки, которые я сохраняю в таблицу с именем EFOT_DISTINCT_COMBOS.

(Раньше это было материализованное представление, но наши администраторы сервера рекомендовали вместо этого использовать простые таблицы, и вручную "refre sh" данных из запросов, используя хранимые процедуры.)

Что мне нужно сделать с этим дальше, это CROSS JOIN, который сталкивается с серьезной проблемой ... сервер блокируется и просто зависает, не выполняя никакой работы ... (блокировка кэша библиотеки?)
Похоже, мне нужно заменить CROSS JOIN в моем запросе и найти лучший способ написать этот запрос.

Этот запрос выглядит как кошмар, но на самом деле он НАМНОГО проще, чем кажется - он просто вычисляет некоторые простые условные итоги.
(Месяц go Я пытался использовать для этого оконные функции, но оконные функции что-то сломалось (я не помню, что именно), поэтому мне пришлось по какой-то причине вернуться к простым агрегатам.)

Таблица, которую мы CROSS JOIN используем, называется SNAPSHOTS, и это очень короткая таблица, содержащая только 44 строки (в конечном итоге она не будет намного больше, возможно, максимум 80-100 строк).
529 032 x 44 = 23 277 408 строк, созданных этим CROSS JOIN.

I попытался уменьшить этот след, добавив HAVING COUNT(ef.TIMESTAMP) > 0 внизу, который удаляет, вероятно, 75% результатов (которые мне не обязательно нужны).
Это определенно помогает, но запрос все равно не выполняется на сервере .

SELECT
    ss.TIMESTAMP,
    ss.TIMESTAMP_DATE,
    fc.FISCAL_QUARTER,
    fc.LOB,
    fc.FREQUENCY,
    fc.EDGE_VP,
    fc.EDGE_RM,
    fc.EDGE_ASM,

    NVL(SUM(ef.PIPELINE),0) AS PIPELINE,
    NVL(SUM(ef.BEST),0) AS BEST,
    NVL(SUM(ef.FORECAST),0) AS FORECAST,
    NVL(SUM(ef.CLOSED),0) AS CLOSED,

    CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.PIPELINE_DIFF),0)
                         WHEN 'D' THEN NVL(SUM(ef.D_PIPELINE_DIFF),0)
                         WHEN 'W' THEN NVL(SUM(ef.W_PIPELINE_DIFF),0)
                         WHEN 'M' THEN NVL(SUM(ef.M_PIPELINE_DIFF),0)
                         WHEN 'Q' THEN NVL(SUM(ef.Q_PIPELINE_DIFF),0)
                         WHEN 'Y' THEN NVL(SUM(ef.Y_PIPELINE_DIFF),0) END AS PIPELINE_CHANGE,

    CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.BEST_DIFF),0)
                         WHEN 'D' THEN NVL(SUM(ef.D_BEST_DIFF),0)
                         WHEN 'W' THEN NVL(SUM(ef.W_BEST_DIFF),0)
                         WHEN 'M' THEN NVL(SUM(ef.M_BEST_DIFF),0)
                         WHEN 'Q' THEN NVL(SUM(ef.Q_BEST_DIFF),0)
                         WHEN 'Y' THEN NVL(SUM(ef.Y_BEST_DIFF),0) END AS BEST_CHANGE,

    CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.FORECAST_DIFF),0)
                         WHEN 'D' THEN NVL(SUM(ef.D_FORECAST_DIFF),0)
                         WHEN 'W' THEN NVL(SUM(ef.W_FORECAST_DIFF),0)
                         WHEN 'M' THEN NVL(SUM(ef.M_FORECAST_DIFF),0)
                         WHEN 'Q' THEN NVL(SUM(ef.Q_FORECAST_DIFF),0)
                         WHEN 'Y' THEN NVL(SUM(ef.Y_FORECAST_DIFF),0) END AS FORECAST_CHANGE,

    CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.CLOSED_DIFF),0)
                         WHEN 'D' THEN NVL(SUM(ef.D_CLOSED_DIFF),0)
                         WHEN 'W' THEN NVL(SUM(ef.W_CLOSED_DIFF),0)
                         WHEN 'M' THEN NVL(SUM(ef.M_CLOSED_DIFF),0)
                         WHEN 'Q' THEN NVL(SUM(ef.Q_CLOSED_DIFF),0)
                         WHEN 'Y' THEN NVL(SUM(ef.Y_CLOSED_DIFF),0) END AS CLOSED_CHANGE,

    CASE WHEN CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.PREV_PIPELINE),0)
                                   WHEN 'D' THEN NVL(SUM(ef.PREV_D_PIPELINE),0)
                                   WHEN 'W' THEN NVL(SUM(ef.PREV_W_PIPELINE),0)
                                   WHEN 'M' THEN NVL(SUM(ef.PREV_M_PIPELINE),0)
                                   WHEN 'Q' THEN NVL(SUM(ef.PREV_Q_PIPELINE),0)
                                   WHEN 'Y' THEN NVL(SUM(ef.PREV_Y_PIPELINE),0) END = 0 THEN 0
                                                                                        ELSE 100 * CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.PIPELINE_DIFF),0)
                                                                                                                        WHEN 'D' THEN NVL(SUM(ef.D_PIPELINE_DIFF),0)
                                                                                                                        WHEN 'W' THEN NVL(SUM(ef.W_PIPELINE_DIFF),0)
                                                                                                                        WHEN 'M' THEN NVL(SUM(ef.M_PIPELINE_DIFF),0)
                                                                                                                        WHEN 'Q' THEN NVL(SUM(ef.Q_PIPELINE_DIFF),0)
                                                                                                                        WHEN 'Y' THEN NVL(SUM(ef.Y_PIPELINE_DIFF),0) END

                                                                                                 / CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.PREV_PIPELINE),0)
                                                                                                                        WHEN 'D' THEN NVL(SUM(ef.PREV_D_PIPELINE),0)
                                                                                                                        WHEN 'W' THEN NVL(SUM(ef.PREV_W_PIPELINE),0)
                                                                                                                        WHEN 'M' THEN NVL(SUM(ef.PREV_M_PIPELINE),0)
                                                                                                                        WHEN 'Q' THEN NVL(SUM(ef.PREV_Q_PIPELINE),0)
                                                                                                                        WHEN 'Y' THEN NVL(SUM(ef.PREV_Y_PIPELINE),0) END END AS PIPELINE_PERCENT_CHANGE,

    CASE WHEN CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.PREV_BEST),0)
                                   WHEN 'D' THEN NVL(SUM(ef.PREV_D_BEST),0)
                                   WHEN 'W' THEN NVL(SUM(ef.PREV_W_BEST),0)
                                   WHEN 'M' THEN NVL(SUM(ef.PREV_M_BEST),0)
                                   WHEN 'Q' THEN NVL(SUM(ef.PREV_Q_BEST),0)
                                   WHEN 'Y' THEN NVL(SUM(ef.PREV_Y_BEST),0) END = 0 THEN 0
                                                                                    ELSE 100 * CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.BEST_DIFF),0)
                                                                                                                    WHEN 'D' THEN NVL(SUM(ef.D_BEST_DIFF),0)
                                                                                                                    WHEN 'W' THEN NVL(SUM(ef.W_BEST_DIFF),0)
                                                                                                                    WHEN 'M' THEN NVL(SUM(ef.M_BEST_DIFF),0)
                                                                                                                    WHEN 'Q' THEN NVL(SUM(ef.Q_BEST_DIFF),0)
                                                                                                                    WHEN 'Y' THEN NVL(SUM(ef.Y_BEST_DIFF),0) END

                                                                                             / CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.PREV_BEST),0)
                                                                                                                    WHEN 'D' THEN NVL(SUM(ef.PREV_D_BEST),0)
                                                                                                                    WHEN 'W' THEN NVL(SUM(ef.PREV_W_BEST),0)
                                                                                                                    WHEN 'M' THEN NVL(SUM(ef.PREV_M_BEST),0)
                                                                                                                    WHEN 'Q' THEN NVL(SUM(ef.PREV_Q_BEST),0)
                                                                                                                    WHEN 'Y' THEN NVL(SUM(ef.PREV_Y_BEST),0) END END AS BEST_PERCENT_CHANGE,

    CASE WHEN CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.PREV_FORECAST),0)
                                   WHEN 'D' THEN NVL(SUM(ef.PREV_D_FORECAST),0)
                                   WHEN 'W' THEN NVL(SUM(ef.PREV_W_FORECAST),0)
                                   WHEN 'M' THEN NVL(SUM(ef.PREV_M_FORECAST),0)
                                   WHEN 'Q' THEN NVL(SUM(ef.PREV_Q_FORECAST),0)
                                   WHEN 'Y' THEN NVL(SUM(ef.PREV_Y_FORECAST),0) END = 0 THEN 0
                                                                                        ELSE 100 * CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.FORECAST_DIFF),0)
                                                                                                                        WHEN 'D' THEN NVL(SUM(ef.D_FORECAST_DIFF),0)
                                                                                                                        WHEN 'W' THEN NVL(SUM(ef.W_FORECAST_DIFF),0)
                                                                                                                        WHEN 'M' THEN NVL(SUM(ef.M_FORECAST_DIFF),0)
                                                                                                                        WHEN 'Q' THEN NVL(SUM(ef.Q_FORECAST_DIFF),0)
                                                                                                                        WHEN 'Y' THEN NVL(SUM(ef.Y_FORECAST_DIFF),0) END

                                                                                                 / CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.PREV_FORECAST),0)
                                                                                                                        WHEN 'D' THEN NVL(SUM(ef.PREV_D_FORECAST),0)
                                                                                                                        WHEN 'W' THEN NVL(SUM(ef.PREV_W_FORECAST),0)
                                                                                                                        WHEN 'M' THEN NVL(SUM(ef.PREV_M_FORECAST),0)
                                                                                                                        WHEN 'Q' THEN NVL(SUM(ef.PREV_Q_FORECAST),0)
                                                                                                                        WHEN 'Y' THEN NVL(SUM(ef.PREV_Y_FORECAST),0) END END AS FORECAST_PERCENT_CHANGE,

    CASE WHEN CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.PREV_CLOSED),0)
                                   WHEN 'D' THEN NVL(SUM(ef.PREV_D_CLOSED),0)
                                   WHEN 'W' THEN NVL(SUM(ef.PREV_W_CLOSED),0)
                                   WHEN 'M' THEN NVL(SUM(ef.PREV_M_CLOSED),0)
                                   WHEN 'Q' THEN NVL(SUM(ef.PREV_Q_CLOSED),0)
                                   WHEN 'Y' THEN NVL(SUM(ef.PREV_Y_CLOSED),0) END = 0 THEN 0
                                                                                      ELSE 100 * CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.CLOSED_DIFF),0)
                                                                                                                      WHEN 'D' THEN NVL(SUM(ef.D_CLOSED_DIFF),0)
                                                                                                                      WHEN 'W' THEN NVL(SUM(ef.W_CLOSED_DIFF),0)
                                                                                                                      WHEN 'M' THEN NVL(SUM(ef.M_CLOSED_DIFF),0)
                                                                                                                      WHEN 'Q' THEN NVL(SUM(ef.Q_CLOSED_DIFF),0)
                                                                                                                      WHEN 'Y' THEN NVL(SUM(ef.Y_CLOSED_DIFF),0) END

                                                                                               / CASE fc.FREQUENCY WHEN '%' THEN NVL(SUM(ef.PREV_CLOSED),0)
                                                                                                                      WHEN 'D' THEN NVL(SUM(ef.PREV_D_CLOSED),0)
                                                                                                                      WHEN 'W' THEN NVL(SUM(ef.PREV_W_CLOSED),0)
                                                                                                                      WHEN 'M' THEN NVL(SUM(ef.PREV_M_CLOSED),0)
                                                                                                                      WHEN 'Q' THEN NVL(SUM(ef.PREV_Q_CLOSED),0)
                                                                                                                      WHEN 'Y' THEN NVL(SUM(ef.PREV_Y_CLOSED),0) END END AS CLOSED_PERCENT_CHANGE -- ,

    -- COUNT(ef.TIMESTAMP) AS DEAL_SS_COUNT

FROM       EFOT_DISTINCT_COMBOS    fc
CROSS JOIN SNAPSHOTS ss
LEFT JOIN  EDGE_FORECAST_OVER_TIME ef

ON  ef.TIMESTAMP = ss.TIMESTAMP
AND ef.fq_selection = NVL(fc.FISCAL_QUARTER,'%')
AND ef.lob_selection = NVL(fc.LOB,'%')
AND ((fc.FREQUENCY = 'D' AND ef.FREQUENCY in('D', 'W', 'M', 'Q', 'Y') AND ef.TIMESTAMP_DATE >= TRUNC(LOCALTIMESTAMP) - INTERVAL '1' MONTH)
  OR (fc.FREQUENCY = 'W' AND TO_CHAR(ef.TIMESTAMP, 'fmDAY') = 'MONDAY' AND ef.TIMESTAMP_DATE >= TRUNC(LOCALTIMESTAMP) - INTERVAL '3' MONTH)
  OR (fc.FREQUENCY = 'M' AND ef.FREQUENCY in('M', 'Q', 'Y') AND ef.TIMESTAMP_DATE >= TRUNC(LOCALTIMESTAMP) - INTERVAL '1' YEAR)
  OR (fc.FREQUENCY = 'Q' AND ef.FREQUENCY in('Q', 'Y'))
  OR ef.FREQUENCY LIKE NVL(fc.FREQUENCY,'%'))
AND ef.EDGE_VP LIKE NVL(fc.EDGE_VP,'%')
AND ef.EDGE_RM LIKE NVL(fc.EDGE_RM,'%')
AND ef.EDGE_ASM LIKE NVL(fc.EDGE_ASM,'%')

WHERE ss.TABLE_NAME = 'EDGE_FORECAST' 

GROUP BY ss.TIMESTAMP      ,
         ss.TIMESTAMP_DATE ,
         fc.FISCAL_QUARTER ,
         fc.LOB            ,
         fc.FREQUENCY      ,
         fc.EDGE_VP        ,
         fc.EDGE_RM        ,
         fc.EDGE_ASM 

HAVING COUNT(ef.TIMESTAMP) > 0;

Затем попытался разделить этот запрос на два запроса.

  • Первый запрос для выполнения CROSS JOIN и создания 23 277 408 строк с 0 для общего числа столбцов.
  • 2-й запрос к UPDATE всем 23 277 408 строкам и вычислению значений для итоговых столбцов.

1-й запрос работал отлично, выполнялся примерно за 12 минут.
Но 2-й запрос стал еще более сложным, он выполнялся почти 6 часов и в конце концов завершился ошибкой:
ORA-01555: snapshot too old.

Есть ли лучший способ написать это, чтобы сервер действительно мог получить работа делает ne?
Этот запрос раньше работал до того, как мы добавили все фильтры LOB (я предполагаю, что один дополнительный фильтр переместил его через край, с точки зрения сложности плана выполнения).

(PasteBin потому что эти запросы слишком длинные для StackOverflow.)
1-й запрос:

2-й запрос

1 Ответ

0 голосов
/ 20 апреля 2020

Гордон Линофф прокомментировал:
"Стоимость дорогостоящего запроса почти всегда связана с перемещением данных - объединениями, объединениями и сортировкой. Существуют исключения. Например, длинные текстовые поля или сложные JSON может добавить значительные накладные расходы, но обычно это перемещение данных. "

Кроме того, Del прокомментировал:
" Несколько вещей после быстрого просмотра, я думаю, ваш запрос слишком verbose. Вы делаете LEFT JOIN для таблицы ef. Но затем ваше предложение HAVING проверяет, что COUNT для этой таблицы> 0. Просто переключите его на INNER JOIN. После этого вы сможете удалить некоторые из них. NVL функционирует во всем коде, если в таблице ef требуется столбец. "

В обоих этих комментариях упоминается объединение как вероятная причина проблем с производительностью.

I следуя совету Дела, удалил предложение HAVING и преобразовал LEFT JOIN в INNER JOIN.
Я также удалил большинство функций NVL, где мог, или консолидировал т Теперь, чтобы упростить запрос.

Только с этими двумя изменениями запрос теперь успешно выполняется за 15 минут, вместо того, чтобы работать часами и, в конечном итоге, завершиться неудачей.
Я готов поставить LEFT JOIN было 99% проблемы.

Спасибо всем, кто нашел время, чтобы прочитать весь мой смешной код и дать мне советы!

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