【问题标题】:Optimization of a complex multiple join query in OracleOracle中复杂多连接查询的优化
【发布时间】:2019-05-12 07:27:42
【问题描述】:

我想优化一个不是我自己编写的旧查询。我的问题是我不习惯这种连接,在两个表之间使用老式 (+) 和多个子句。目前,该查询大约需要 15 分钟才能执行,因为每个表中有很多行。

SELECT * 
FROM A, B, C, D, E, F, G
WHERE A.id = B.id
  AND C.id = B.id
  AND A.daytime >= C.daytime
  AND (C.end_date IS NULL OR A.daytime < C.end_date)
  AND A.id = D.id(+)
  AND A.daytime = D.daytime(+)
  AND A.id = E.id
  AND A.daytime = E.daytime(+)
  AND A.id = F.id
  AND A.daytime = F.daytime(+)
  AND custom_function(A.id, 'O', A.daytime) = G.id(+)
  AND A.daytime = G.daytime(+)
  AND A.classname IN('X','Y','Z');

我不希望有人为我重写查询,而只是为了指导我:

  • 我可以优化这样的查询吗?
  • 如果是这样,我应该使用多个子查询吗?

我尝试了一组复杂的内连接和外连接,但我无法真正理解我在做什么。 任何帮助将不胜感激。

编辑

其实问题出在SELECT子句上,因为我在真正的查询中并没有使用SELECT *,而是一堆外部函数应用于列,它们是执行所需时间的原因.谢谢大家,但我的问题没有解决方案。

【问题讨论】:

  • 重写为显式join 语法很好,但对性能没有帮助。我会开始看custom_function
  • @HoneyBadger 好吧,这就是我所担心的。我无法触及此功能。因此查询已经是最优的吧?
  • 查询看起来很简单,但您应该检查执行计划。
  • @HoneyBadger custom_function 似乎对执行没有任何影响
  • 在这种情况下你需要回到执行计划看看能做什么。

标签: sql join oracle11g


【解决方案1】:

您调用custom_function 的唯一参数来自A。

如果您执行以下操作,调用次数可能会减少:

SELECT * 
FROM (
SELECT A.* (SELECT custom_function(id, 'O', daytime) FROM dual) AS cf FROM A WHERE classname IN('X','Y','Z')
) A_Alias
, B, C, D, E, F, G
WHERE A_Alias.id = B.id
  AND C.id = B.id
  AND A_Alias.daytime >= C.daytime
  AND (C.end_date IS NULL OR A_Alias.daytime < C.end_date)
  AND A_Alias.id = D.id(+)
  AND A_Alias.daytime = D.daytime(+)
  AND A_Alias.id = E.id
  AND A_Alias.daytime = E.daytime(+)
  AND A_Alias.id = F.id
  AND A_Alias.daytime = F.daytime(+)
  AND A_Alias.cf = G.id(+)
  AND A_Alias.daytime = G.daytime(+);

这将通过消除 JOIN 的记录倍增效应和确保从 A 中过滤掉尽可能多的行(classname 上的条件)来减少计数。

注意:我还包含了来自here.的优化
它可能没有效果,但值得测试。
搜索名为:Scalar Subquery Caching & Scalar Subquery Caching (Revisited) 的部分(我邀请您阅读全文)。

【讨论】:

  • 您好,我已经尝试过您的建议,看起来非常好,但不幸的是,查询所用的时间完全相同。不过非常感谢您的帮助。
  • 其实无论AND custom_function(A.id, 'O', A.daytime) = G.id(+)是否存在,查询都需要同样的时间
  • 刚刚看到您的评论(真正的查询是带有外部函数的 SELECT)。您确定即使在这种情况下,您也不能从子查询中调用它们(= 您在 JOIN 中乘以记录之前)?它适用的条件:它们是确定性的(= 当使用相同的参数调用时,结果永远不会改变)+ 它们没有副作用(= 无论您调用它们一次还是 1k 次,您系统的后置条件是不变)+ 传递的参数来自 1 个表或您需要的所有表的至少一个子集。
  • 是的,我确定。我删除了 80% 的我并不真正需要的列,我的查询现在执行时间减少了 7 倍:这就是我的需要。真的非常感谢您花时间提供帮助。
猜你喜欢
  • 2021-12-11
  • 1970-01-01
  • 2020-04-30
  • 2012-01-07
  • 1970-01-01
  • 1970-01-01
  • 2012-09-22
相关资源
最近更新 更多