简体   繁体   English

oracle 中的查询优化

[英]Query Optimization in oracle

I need to fetch result from one tables and one view joined on 2 columns.我需要从一张表中获取结果,并在 2 列上加入一个视图。

View: 8million records Table: 5K Records查看:800 万条记录表:5K 条记录

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.如果没有解释计划或模式/DDL,可以进行的优化是有限的。

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.查询的另一个可能的重构......我不知道 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

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?您对JOINWHEREGROUP BY子句中使用的字段有索引吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM