Oracle 查询优化帮助 - 多遍

Posted

技术标签:

【中文标题】Oracle 查询优化帮助 - 多遍【英文标题】:Oracle Query Optimization Help - Multi Pass 【发布时间】:2010-08-04 21:07:30 【问题描述】:

我需要查询订单表以获取昨天交易的所有订单的计数,按发货日期分组。然后我需要有一个额外的列来给出所有交易的发货日期的总订单。当我添加第二列时,处理时间呈指数增长(这是预期的)到 109 秒。有什么办法可以改进这个 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)。

【问题讨论】:

请说明shipping_dateorder_date 字段(内部查询)来自哪个表。 我已根据您的要求编辑了上面的 SQL。谢谢。 【参考方案1】:

如果您只是在寻找类似的输出:

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 同时调用条件计数。

【讨论】:

是的,但这会显示所有发货日期。我只想显示昨天订单的发货日期。 对不起,我忽略了这一点。我更新了代码,以便只返回昨天至少有一个订单的发货日期。【参考方案2】:

我将您的查询改写为:

   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;

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

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

【讨论】:

谢谢,OMG 小马们。此查询现在在 0.78 秒内返回。只是为了确定一下,是否由于最后一次连接而加速,您将 where 约束变成了连接约束的一部分? @Bradford:是的 - 转换为不同的数据类型肯定会影响性能,尤其是当您想要加入该信息时。

以上是关于Oracle 查询优化帮助 - 多遍的主要内容,如果未能解决你的问题,请参考以下文章

需要帮助在 12c 中优化 Oracle 查询

oracle查询的查询优化

请帮助优化查询

关于优化在大量数据上执行的 Oracle SQL 查询的建议/技巧

使用 NOT IN(Oracle Sql Developer)的查询性能优化

oracle 优化时间查询