Oracle SQL - 任何人都可以提高效率吗?

时间:2014-04-23 08:15:14

标签: sql performance oracle query-optimization

这有点味道 - 这是一个从水晶报告中调用的查询,该报告使用分成两个纸箱的纸箱编号进行搜索并返回纸箱编号,数量,从原始数量中删除的数量,用户和拖车号码,如果它已经加载到一个。

查询的第一部分效果很好,遗憾的是所有数据都会在30天后归档,并且存档量很大!添加归档部分后,此查询可能需要30到45分钟才能运行,这太长了。任何人都可以帮我优化这个查询,以便它可以更快地运行吗?

非常感谢,7岁。

SELECT *
FROM
  (SELECT menu_optn_name,
          tran_nbr,
          seq_nbr,
          cntr_nbr,
          ch.total_qty ,
          ptt.create_date_time,
          um.user_name,
          ch.trlr_nbr,

     (SELECT sum(ref_field_2)
      FROM prod_trkg_tran
      WHERE menu_optn_name = 'RF Split/Comb {Carton}'
        AND cntr_nbr = '0030651942') AS Total
   FROM prod_trkg_tran ptt
   INNER JOIN user_master um ON um.emplye_id = ptt.user_id
   LEFT OUTER JOIN carton_hdr ch ON ch.carton_nbr = ptt.cntr_nbr
   WHERE menu_optn_name = 'RF Split/Comb {Carton}'
     AND ptt.cntr_nbr = '0030651942'
   GROUP BY menu_optn_name,
            tran_nbr,
            seq_nbr,
            cntr_nbr,
            ch.total_qty,
            ptt.create_date_time,
            um.user_name,
            ch.trlr_nbr
   UNION SELECT menu_optn_name,
                tran_nbr,
                seq_nbr,
                cntr_nbr,
                ch.total_qty,
                ptt.create_date_time,
                um.user_name,
                ch.trlr_nbr,

     (SELECT sum(ref_field_2)
      FROM prod_trkg_tran
      WHERE menu_optn_name = 'RF Split/Comb {Carton}'
        AND cntr_nbr NOT IN
          (SELECT cntr_nbr
           FROM prod_trkg_tran ptt
           LEFT OUTER JOIN carton_hdr ch ON ch.carton_nbr = ptt.cntr_nbr
           WHERE menu_optn_name = 'RF Split/Comb {Carton}'
             AND ptt.cntr_nbr = '0030651942')
        AND tran_nbr IN
          (SELECT tran_nbr
           FROM prod_trkg_tran ptt
           LEFT OUTER JOIN carton_hdr ch ON ch.carton_nbr = ptt.cntr_nbr
           WHERE menu_optn_name = 'RF Split/Comb {Carton}'
             AND ptt.cntr_nbr = '0030651942')) AS Total
   FROM prod_trkg_tran ptt
   INNER JOIN user_master um ON um.emplye_id = ptt.user_id
   LEFT OUTER JOIN carton_hdr ch ON ch.carton_nbr = ptt.cntr_nbr
   WHERE cntr_nbr NOT IN
       (SELECT cntr_nbr
        FROM prod_trkg_tran ptt
        LEFT OUTER JOIN carton_hdr ch ON ch.carton_nbr = ptt.cntr_nbr
        WHERE menu_optn_name = 'RF Split/Comb {Carton}'
          AND ptt.cntr_nbr = '0030651942')
     AND tran_nbr IN
       (SELECT tran_nbr
        FROM prod_trkg_tran ptt
        LEFT OUTER JOIN carton_hdr ch ON ch.carton_nbr = ptt.cntr_nbr
        WHERE menu_optn_name = 'RF Split/Comb {Carton}'
          AND ptt.cntr_nbr = '0030651942')
   GROUP BY menu_optn_name,
            tran_nbr,
            seq_nbr,
            cntr_nbr,
            ch.total_qty,
            ptt.create_date_time,
            um.user_name,
            ch.trlr_nbr)
UNION
SELECT *
FROM
  (SELECT menu_optn_name,
          tran_nbr,
          seq_nbr,
          cntr_nbr,
          ch.total_qty,
          ptt.create_date_time,
          um.user_name,
          ch.trlr_nbr,

     (SELECT sum(ref_field_2)
      FROM wm_archive.prod_trkg_tran@awm.corp.*******.com
      WHERE menu_optn_name = 'RF Split/Comb {Carton}'
        AND cntr_nbr = '0030651942') AS Total
   FROM wm_archive.prod_trkg_tran@awm.corp.*******.com ptt
   INNER JOIN user_master um ON um.emplye_id = ptt.user_id
   LEFT OUTER JOIN carton_hdr ch ON ch.carton_nbr = ptt.cntr_nbr
   WHERE menu_optn_name = 'RF Split/Comb {Carton}'
     AND ptt.cntr_nbr = '0030651942'
   GROUP BY menu_optn_name,
            tran_nbr,
            seq_nbr,
            cntr_nbr,
            ch.total_qty,
            ptt.create_date_time,
            um.user_name,
            ch.trlr_nbr
   UNION SELECT menu_optn_name,
                tran_nbr,
                seq_nbr,
                cntr_nbr,
                ch.total_qty,
                ptt.create_date_time,
                um.user_name,
                ch.trlr_nbr,

     (SELECT sum(ref_field_2)
      FROM wm_archive.prod_trkg_tran@awm.corp.*******.com
      WHERE menu_optn_name = 'RF Split/Comb {Carton}'
        AND cntr_nbr NOT IN
          (SELECT cntr_nbr
           FROM wm_archive.prod_trkg_tran@awm.corp.*******.com ptt
           LEFT OUTER JOIN wm_archive.carton_hdr@awm.corp.*******.com ch ON ch.carton_nbr = ptt.cntr_nbr
           WHERE menu_optn_name = 'RF Split/Comb {Carton}'
             AND ptt.cntr_nbr = '0030651942')
        AND tran_nbr IN
          (SELECT tran_nbr
           FROM wm_archive.prod_trkg_tran@awm.corp.*******.com ptt
           LEFT OUTER JOIN wm_archive.carton_hdr@awm.corp.*******.com ch ON ch.carton_nbr = ptt.cntr_nbr
           WHERE menu_optn_name = 'RF Split/Comb {Carton}'
             AND ptt.cntr_nbr = '0030651942')) AS Total
   FROM wm_archive.prod_trkg_tran@awm.corp.*******.com ptt
   INNER JOIN user_master um ON um.emplye_id = ptt.user_id
   LEFT OUTER JOIN wm_archive.carton_hdr@awm.corp.*******.com ch ON ch.carton_nbr = ptt.cntr_nbr
   WHERE cntr_nbr NOT IN
       (SELECT cntr_nbr
        FROM wm_archive.prod_trkg_tran@awm.corp.*******.com ptt
        LEFT OUTER JOIN wm_archive.carton_hdr@awm.corp.*******.com ch ON ch.carton_nbr = ptt.cntr_nbr
        WHERE menu_optn_name = 'RF Split/Comb {Carton}'
          AND ptt.cntr_nbr = '0030651942')
     AND tran_nbr IN
       (SELECT tran_nbr
        FROM wm_archive.prod_trkg_tran@awm.corp.*******.com ptt
        LEFT OUTER JOIN wm_archive.carton_hdr@awm.corp.*******.com ch ON ch.carton_nbr = ptt.cntr_nbr
        WHERE menu_optn_name = 'RF Split/Comb {Carton}'
          AND ptt.cntr_nbr = '0030651942')
   GROUP BY menu_optn_name,
            tran_nbr,
            seq_nbr,
            cntr_nbr,
            ch.total_qty,
            ptt.create_date_time,
            um.user_name,
            ch.trlr_nbr)
WHERE rownum <=2;

1 个答案:

答案 0 :(得分:0)

我看到这个查询有两种可能的优化。

首先是:

SELECT key, (SELECT SUM(value) FROM table WHERE condition) AS Total
FROM table WHERE condition
GROUP BY key

在功能上等同于:

SELECT key, SUM(value)
FROM table WHERE condition
GROUP BY key

......但可能效率低得多。

第二个是:

SELECT x,y,z FROM table WHERE condition_1 GROUP BY x,y
UNION
SELECT x,y,z FROM table WHERE condition_2 GROUP BY x,y

在功能上等同于:

SELECT x,y,z FROM table WHERE condition_1 OR condition_2 GROUP BY x,y

也就是说,如果condition_1和condition_2只引用出现在GROUP BY子句中的列,就像你的情况一样。顺序可能存在一些差异,但如果需要,可以使用显式ORDER BY子句来解决这些差异。

也就是说,消除4个子选择和2个联合似乎是可能的。考虑到WHERE过滤器的所有列都位于prod_trkg_tran表中,您还可以删除一些LEFT JOIN。所以它看起来像这样:

   select * from (
         select menu_optn_name, tran_nbr, seq_nbr, cntr_nbr, ch.total_qty, ptt.create_date_time, um.user_name, ch.trlr_nbr, sum(ref_field_2) as Total
         from            prod_trkg_tran ptt
         inner join      user_master    um  on um.emplye_id = ptt.user_id
         left outer join carton_hdr     ch  on ch.carton_nbr = ptt.cntr_nbr
         where (menu_optn_name = 'RF Split/Comb {Carton}' and ptt.cntr_nbr = '0030651942') or (
            cntr_nbr not in (
               select cntr_nbr
               from prod_trkg_tran
               where menu_optn_name = 'RF Split/Comb {Carton}' and cntr_nbr = '0030651942'
            ) and
            tran_nbr in (
               select tran_nbr
               from prod_trkg_tran 
               where menu_optn_name = 'RF Split/Comb {Carton}' and cntr_nbr = '0030651942'
            )
         )
         group by menu_optn_name, tran_nbr, seq_nbr, cntr_nbr, ch.total_qty, ptt.create_date_time, um.user_name, ch.trlr_nbr
   )
union
   select * from (
         select menu_optn_name, tran_nbr, seq_nbr, cntr_nbr, ch.total_qty, ptt.create_date_time, um.user_name, ch.trlr_nbr, sum(ref_field_2) as Total
         from            wm_archive.prod_trkg_tran@awm.corp.*******.com ptt
         inner join      user_master                                    um  on um.emplye_id = ptt.user_id
         left outer join carton_hdr                                     ch  on ch.carton_nbr = ptt.cntr_nbr
         where (menu_optn_name = 'RF Split/Comb {Carton}' and ptt.cntr_nbr = '0030651942') or (
            cntr_nbr not in (
               select cntr_nbr
               from wm_archive.prod_trkg_tran@awm.corp.*******.com
               where menu_optn_name = 'RF Split/Comb {Carton}' and cntr_nbr = '0030651942'
            ) and
            tran_nbr in (
               select tran_nbr
               from wm_archive.prod_trkg_tran@awm.corp.*******.com ptt
               where menu_optn_name = 'RF Split/Comb {Carton}' and cntr_nbr = '0030651942'
            )
         )
         group by menu_optn_name, tran_nbr, seq_nbr, cntr_nbr, ch.total_qty, ptt.create_date_time, um.user_name, ch.trlr_nbr
   )
where rownum <=2;

还有第三个优化。 user_master上的INNER JOIN可以从内部选择移出到外部联合。但我怀疑这次加入的成本是多少。