Oracle查询优化帮助 - 多次通过

时间:2010-08-04 21:07:31

标签: sql oracle plsql query-optimization

我需要查询订单表以获取昨天交易的所有订单的计数,按发货日期分组。然后我需要一个额外的列来给出所有交易的发货日期的总订单。当我添加第二列时,处理时间呈指数增长(预期为)到109s。有什么办法可以改进这个SQL吗?我只是想知道我是否遗漏了任何根本的东西。

SELECT t.shipping_date
       , t.net_orders
       , count(*) as total_orders
FROM (
    SELECT   s.store_num
             , s.store_cd
             , to_char(o.shipping_date, 'MM/DD/YYYY') as shipping_date
             , COUNT (*) as net_orders
    FROM order o left 
           join store s 
                on ( s.store_num = o.store_num )
    WHERE TRUNC (o.order_date) = TRUNC (SYSDATE - 1)
    AND s.store_cd = 'ZZZ'
    AND o.status in ('A', 'B')
    GROUP BY s.store_num
             , s.store_cd
             , to_char(shipping_date, 'MM/DD/YYYY')
) t
LEFT JOIN order o ON 
          ( TRUNC (o.shipping_date) = to_date(t.shipping_date, 'MM/DD/YYYY') 
            and o.store_num = t.store_num )
WHERE o.status in ('A', 'B')
GROUP BY t.shipping_date, t.net_orders;

除了以下表达式之外,我在所有这些列上都有索引:TRUNC(order_date)和TRUNC(shipping_date)。

2 个答案:

答案 0 :(得分:3)

如果您只是寻找输出:

shipping_date      net_orders     total_orders
01-AUG-2004        14             37
02-AUG-2004        17             29
03-AUG-2004        19             43

如何:

SELECT *
  FROM (
    SELECT TRUNC(o.shipping_date) as shipping_date
         , COUNT(CASE WHEN TRUNC(o.order_date) = TRUNC(SYSDATE - 1) 
                      THEN 1 
                      ELSE NULL 
                  END) as net_orders -- count does not count NULL values.
         , COUNT(*) as total_orders
      FROM order o 
           LEFT JOIN 
           store s 
              on s.store_num = o.store_num
     WHERE s.store_cd = 'ZZZ'
       AND o.status in ('A', 'B')
     GROUP BY TRUNC(o.shipping_date)
   ) 
WHERE net_orders > 0 -- only shipping dates that had at least one order yesterday

它可以避免额外的联接回到订单表,因为无论如何你将不得不触摸商店的所有订单,当你获得总数时,你也可以做我所做的事情。 d同时调用条件计数。

答案 1 :(得分:1)

我将您的查询重写为:

   SELECT t.shipping_date, 
          t.net_orders, 
          COUNT(*) as total_orders 
     FROM (SELECT s.store_num, 
                  s.store_cd, 
                  o.status,
                  TRUNC(o.shipping_date) AS shipping_date, 
                  COUNT (*) as net_orders
             FROM STORE s
             JOIN ORDER o ON o.store_num = s.store_num
                         AND o.status IN ('A', 'B')
            WHERE s.store_cd = 'ZZZ'
              AND TRUNC(order_date) = TRUNC (SYSDATE - 1)
  GROUP BY s.store_num, s.store_cd, TRUNC(shipping_date)) t
LEFT JOIN ORDER o ON TRUNC(o.shipping_date) = t.shipping_date
                 AND o.store_num = t.store_num
                 AND o.status = t.status
 GROUP BY t.shipping_date, t.net_orders;

一些小的重新安排,但我确实摆脱了TO_CHAR(shipping_date),后来转换回DATE。 TRUNC(shipping_date)是相同的,并简化了操作。

使用函数加入条件不会使用索引 - 您需要创建一个与JOIN条件匹配的基于函数的索引。