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_date
和order_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 查询优化帮助 - 多遍的主要内容,如果未能解决你的问题,请参考以下文章
关于优化在大量数据上执行的 Oracle SQL 查询的建议/技巧