优化SQL连接中的子查询

问题描述 投票:0回答:1

我正在努力优化当前使用多个子查询的查询。子查询单独运行速度很快,但是当组合在一起时,速度非常慢。下面我概述了一组示例数据和我当前的查询。

查询目的

显示订单上发生不同事件的日期

数据结构

有一个订单表和一个订单历史表

订单

订购 部分 状态
1 A 计划中
2 B 已发布
3 A 已关闭
4 B 已发布
5 C 已关闭

订单历史

时间戳 订购 留言 新状态
10:00 上午 1 已创建 计划中
上午10点15分 2 已创建 计划中
上午10点16分 2 状态已更改 已发布
上午10点20分 3 已创建 计划中
上午10点24分 3 状态已更改 已发布
上午10点25分 2 状态已更改 计划中
上午10点30分 4 已创建 计划中
上午10点35分 3 状态已更改 已关闭
10:40 上午 5 已创建 计划中
上午 10:45 4 状态已更改 已发布
上午10点50分 5 状态已更改 已发布
上午10点55分 2 状态已更改 已发布
11:00 上午 5 状态已更改 计划中
11:05am 5 状态已更改 已发布
上午11点15分 5 状态已更改 已关闭
上午11点20分 3 状态已更改 已发布
上午11点25分 3 状态已更改 已关闭

想要的结果

订购 部分 状态 创建日期 首次发布 最新发布 截止日期
1 A 计划中 10:00 上午
2 B 已发布 上午10点15分 上午10点16分 上午10点55分
3 A 已关闭 上午10点20分 上午10点24分 上午11点20分 上午11点25分
4 B 已发布 上午10点30分 上午 10:45 上午 10:45
5 C 已关闭 10:40 上午 上午10点50分 11:05am 上午11点15分

当前查询

我当前的查询针对每个时间戳字段(已创建、首次发布、最新发布、已关闭)对历史表进行子查询,然后将它们全部连接起来:

SELECT 
c.order
,c.part
,c.status
,c.cDate
,fr.frDate
,lr.lrDate
,cd.cdDate
FROM
(SELECT 
 o.order
 ,o.part
 ,o.status
 ,min(oh.timestamp)
 FROM order o
 JOIN order_history oh
 ON o.order = oh.order
 WHERE oh.message = 'Created' AND oh.NewStatus = 'Planned'
 group by o.order, o.part, o.status) c
JOIN 
(SELECT 
 o.order
 ,o.part
 ,o.status
 ,min(oh.timestamp)
 FROM order o
 JOIN order_history oh
 ON o.order = oh.order
 WHERE oh.message = 'Status Changed' AND oh.NewStatus = 'Released'
 group by o.order, o.part, o.status) fr
ON c.order = fr.order and c.part = fr.part and c.status = fr.status
JOIN 
(SELECT 
 o.order
 ,o.part
 ,o.status
 ,max(oh.timestamp)
 FROM order o
 JOIN order_history oh
 ON o.order = oh.order
 WHERE oh.message = 'Status Changed' AND oh.NewStatus = 'Released'
 group by o.order, o.part, o.status) lr
ON c.order = lr.order and c.part = lr.part and c.status = lr.status
JOIN 
(SELECT 
 o.order
 ,o.part
 ,o.status
 ,max(oh.timestamp)
 FROM order o
 JOIN order_history oh
 ON o.order = oh.order
 WHERE oh.message = 'Status Changed' AND oh.NewStatus = 'Closed'
 group by o.order, o.part, o.status) cd
ON c.order = cd.order and c.part = cd.part and c.status = cd.status

所以如你所见...它很丑!而且真的很慢。我可以做什么来优化?

请记住,这是一个非常简化的假示例。我试图展示数据和查询的复杂性。如果查询中存在错误,我深表歉意,但我可以验证当前查询是否确实可以给我想要的结果,所以我不只是寻求更正,而是寻求优化。

sql oracle join subquery query-optimization
1个回答
0
投票

如果不访问真实的查询、表和索引结构以及执行计划,就不可能优化查询。"然而,简化它以删除子查询并减少连接数量不太可能造成伤害� 755e �并且可能为您提供一个更好的地方来开始调查计划并寻找真正的优化机会。

\n"

您的“简化的假”版本使用非法标识符并具有各种其他错误(包括需要外连接才能返回所有五行),您说忽略这些错误,但正如米奇评论的那样,这些事情和一般的虚假使它变得毫无用处。尽管如此,作为从哪里开始的一般想法,也许,对于您的示例,您可以使用条件聚合重写它,例如:

SELECT 
o.order_num
,o.part
,o.status
,MIN(CASE WHEN oh.message = 'Created' AND oh.NewStatus = 'Planned' THEN oh.timestamp END) AS cDate
,MIN(CASE WHEN oh.message = 'Status Changed' AND oh.NewStatus = 'Released' THEN oh.timestamp END) AS frDate
,MAX(CASE WHEN oh.message = 'Status Changed' AND oh.NewStatus = 'Released' THEN oh.timestamp END) AS lrDate
,MAX(CASE WHEN oh.message = 'Status Changed' AND oh.NewStatus = 'Closed' THEN oh.timestamp END) AS cdDate
FROM orders o
LEFT JOIN order_history oh
ON o.order_num = oh.order_num
GROUP BY o.order_num, o.part, o.status
ORDER BY o.order_num, o.part, o.status
ORDER_NUM 部分 状态 CD日期 FRDATE LRDATE CD日期
1 A 计划中 10:00 上午
2 B 已发布 上午10点15分 上午10点16分 上午10点55分
3 A 关闭 上午10点20分 上午10点24分 上午11点20分 上午11点25分
4 B 已发布 上午10点30分 上午 10:45 上午 10:45
5 C 已关闭 10:40 上午 上午10点50分 11:05am 上午11点15分

fiddle 包括带有合法标识符的查询的工作版本(尽管“时间戳”仍然不理想)和其他更改,以及此修改后的查询。

(这适用于“时间戳”作为带有假值的字符串,但也适用于真实日期或时间戳,或者当然。如果总是有“已创建”记录,则不一定需要是外部联接,这似乎是可能的。)

© www.soinside.com 2019 - 2024. All rights reserved.