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?
精彩评论