Оптимизация запросов в Oracle - PullRequest
0 голосов
/ 07 июня 2011

Мне нужно получить результат из одной таблицы и одного представления, объединенного в 2 столбца.

Просмотр: 8 миллионов записей Таблица: 5K записей

Я просмотрел план запроса и заметил, что выполнение запроса займет очень много времени, и фактически попытался выполнить этот запрос, но не получил никакого результата.

Пожалуйста, помогите мне оптимизировать запрос. Я не использую подсказки.

SELECT coupon_upc
     , sum ( loyalty_a ) a
     , sum ( loyalty_b ) b
     , sum ( loyalty_c ) c
     , sum ( loyalty_x )
  FROM ( SELECT ccd.coupon_upc                                        AS coupon_upc
              , ( CASE WHEN a.loyalty_cell = 'A' then 1 else 0 end )  AS loyalty_a
              , ( CASE WHEN a.loyalty_cell = 'B' then 1 else 0 end )  AS loyalty_b
              , ( CASE WHEN a.loyalty_cell = 'C1' then 1 else 0 end ) AS loyalty_c
              , ( CASE WHEN a.loyalty_cell = 'X' then 1 else 0 end )  AS loyalty_x
           FROM view1 a
              , ( select distinct coupon_upc
                                , coupon_id
                                , division
                             from table2
                            where schedule_key = 'XXX' ) ccd
          WHERE a.campaign_code = 'XXX'
            AND a.coupon_id = ccd.coupon_id
            AND a.division = ccd.division ) a
 GROUP BY coupon_upc

Ответы [ 2 ]

1 голос
/ 07 июня 2011

Другое возможное переписывание будет:

SELECT
    map.coupon_upc
  , COUNT(CASE WHEN a.loyalty_cell = 'A' THEN 1 ELSE NULL END) AS loyalty_a
  , COUNT(CASE WHEN a.loyalty_cell = 'B' THEN 1 ELSE NULL END) AS loyalty_b
  , COUNT(CASE WHEN a.loyalty_cell = 'C1' THEN 1 ELSE NULL END) AS loyalty_c
  , COUNT(CASE WHEN a.loyalty_cell = 'X' THEN 1 ELSE NULL END) AS loyalty_x
FROM
  ( SELECT coupon_upc, coupon_id, division
    FROM table2 WHERE schedule_key = 'xxx'
    GROUP BY coupon_upc, coupon_id, division
  ) AS map
  JOIN view1 a
    ON a.coupon_id = map.coupon_id
    AND a.division = map.division
WHERE
    a.campaign_code = 'xxx'  
GROUP BY
    map.coupon_upc

Есть ли у вас индексы для полей, которые используются в предложениях JOIN, WHERE и GROUP BY?

1 голос
/ 07 июня 2011

Без плана объяснения или схемы / DDL существует ограниченный объем оптимизации, который можно выполнить.

Вот альтернативный вариант, но вам нужно проверить его, чтобы убедиться, что он делаетлюбая разница.(Замените объединение на коррелированный подзапрос.)

SELECT
  coupon_upc, sum(loyalty_a) a, sum(loyalty_b) b, sum(loyalty_c) c, sum(loyalty_x) x
FROM
  (
  SELECT
    (
    SELECT
      coupon_upc
    FROM
      table2
    WHERE
      schedule_key  = 'XXX'
      AND coupon_id = a.coupon_id
      AND division  = a.division
    GROUP BY
      coupon_upc
    ) as coupon_upc,
    (case when a.loyalty_cell = 'A'  then 1 else 0 end) as loyalty_a,
    (case when a.loyalty_cell = 'B'  then 1 else 0 end) as loyalty_b,
    (case when a.loyalty_cell = 'C1' then 1 else 0 end) as loyalty_c,
    (case when a.loyalty_cell = 'X'  then 1 else 0 end) as loyalty_x
  FROM
    view1 a
  WHERE
    a.campaign_code = 'XXX'    
) a
GROUP BY
  coupon_upc

Кроме этого, возможны следующие виды оптимизации:
- сохранение представления
- индексы
- рефакторинг структур данных

РЕДАКТИРОВАТЬ

Еще один возможный рефакторинг запроса ... Я не знаю, насколько хорошо Oracle оптимизирует 4 экземпляра коррелированных подзапросов.

SELECT
  coupon_upc,
  SUM((SELECT COUNT(*) FROM view1 WHERE campaign_code = 'XXX' AND loyalty_cell = 'A'  AND coupon_id = map.coupon_id AND division = map.division)) AS loyalty_a,
  SUM((SELECT COUNT(*) FROM view1 WHERE campaign_code = 'XXX' AND loyalty_cell = 'B'  AND coupon_id = map.coupon_id AND division = map.division)) AS loyalty_b,
  SUM((SELECT COUNT(*) FROM view1 WHERE campaign_code = 'XXX' AND loyalty_cell = 'C1' AND coupon_id = map.coupon_id AND division = map.division)) AS loyalty_c,
  SUM((SELECT COUNT(*) FROM view1 WHERE campaign_code = 'XXX' AND loyalty_cell = 'X'  AND coupon_id = map.coupon_id AND division = map.division)) AS loyalty_x
FROM
  (
  SELECT coupon_upc, coupon_id, division
  FROM table2 WHERE schedule_key = 'xxx'
  GROUP BY coupon_upc, coupon_id, division
  )
  AS map
GROUP BY
  coupon_upc

Или, может быть ...

SELECT
  map.coupon_upc, SUM(data.loyalty_a) AS a, SUM(data.loyalty_b) AS b, SUM(data.loyalty_c) AS c, SUM(data.loyalty_x) AS X
FROM
  (
  SELECT coupon_upc, coupon_id, division
  FROM table2 WHERE schedule_key = 'xxx'
  GROUP BY coupon_upc, coupon_id, division
  )
  AS map
INNER JOIN
  (
  SELECT
    coupon_id,
    division,
    SUM(CASE WHEN loyalty_cell = 'A'  THEN 1 ELSE 0 END) AS loyalty_a,
    SUM(CASE WHEN loyalty_cell = 'B'  THEN 1 ELSE 0 END) AS loyalty_b,
    SUM(CASE WHEN loyalty_cell = 'C1' THEN 1 ELSE 0 END) AS loyalty_c,
    SUM(CASE WHEN loyalty_cell = 'X'  THEN 1 ELSE 0 END) AS loyalty_x
  FROM
    view1
  WHERE
    campaign_code = 'XXX'
  )
  AS data
    ON  data.coupon_id = map.coupon_id
    AND data.division  = map.division
GROUP BY
  map.coupon_upc
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...