开发者

Query Optimization in oracle

I need to fetch result from one tables and one view joined on 2 columns.

View: 8million records Table: 5K Records

I went through query plan and observe that query will take very long to run and infact try to run this query but not getting any result.

Please help me in optimize the query.I am not using any hint.

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


Without the explain plan, or the schema/DDL, there is a limitted amount of optimisation that can be done.

Here is an alternative, but you'd need to test it to see if it makes any difference. (Replace a join with a correlated sub-query.)

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

Other than that, the kind of optimisations are:
- persisting the view
- indexes
- refactoring data structures

EDIT

Another possible refactor of the query... I don't know how well Oracle would optimise the 4 instances of correlated sub-queries.

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

Or maybe...

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


Another possible rewrite would be:

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

Do you have indexes on the fields that are used in the JOIN, WHERE and the GROUP BY clauses?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜