3

更新 11/2

12c在进行了一些额外的故障排除后,我的团队能够将这个 Oracle 错误直接与查询停止工作前一天晚上对数据库进行的参数更改联系起来。在遇到与该数据库相关的应用程序的一些性能问题后,我的团队让我们的 DBA 将OPTIMIZER_FEATURES_ENABLE参数从更改12.1.0211.2.0.4. 这解决了问题应用程序的性能问题,但导致了我上面描述的错误。为了验证,我已经能够通过更改此参数在单独的环境中复制同样的问题。我的 DBA 已向 Oracle 提交了一张票,以查看此问题。

作为一种解决方法,我可以对查询进行轻微更改以检索预期结果。具体来说,我结合Subquery1Subquery2把一些谓词Subquery1WHERE子句移到了JOIN(它们更合适的地方)。此更改编辑了我的执行计划(它的效率略低于之前列出的内容),但足以解决最初的问题。


原帖

首先,让我为这个问题的任何含糊之处道歉,但我正在处理一个机密的金融系统,所以我不得不隐藏某些实施细节。

背景

我有一个Oracle很久以前投入生产的查询,最近在升级11g12c. 据我(和我的生产支持团队)所知,此查询在此之前已经运行了一年多。

细节

查询过于复杂且效率不高,但这在很大程度上是因为我正在处理非规范化表(历史上以大型机建模)和来自上游系统的不良数据输入。为了处理复杂的业务情况,我利用了多个级别的子查询因子(WITH语句),然后我的最终语句将两个内联视图连接在一起。没有所有复杂谓词的查询的基本结构如下:

我有 3 张桌子Table1, Table2, Table3. Table1是一个处理表,由来自 的记录组成Table2

--This grabs a subset from Table1
WITH Subquery1 as (
   SELECT FROM Table1),

--This eliminates certain records from the first subset based on sister records 
--from the original source table 
Subquery2 as (
   SELECT FROM Subquery1
   WHERE NOT EXISTS FROM (SELECT from Table2)),

--This ties the records from Subquery2 to Table3
Subquery3 as (
   SELECT FROM Table3
   JOIN (SELECT Max(Date) FROM Table3)
   JOIN Subquery2)

--This final query evaluates subquery3 in two different ways and 
--only takes those records which fit the criteria items from both sets
SELECT FROM 
(SELECT FROM Subquery3)             -- Call this Inline View A
JOIN (SELECT FROM Subquery3)        -- Call this Inline View B

最后的查询非常基本:

   SELECT A.Group_No, B.Sub_Group, B.Key, B.Lob               
   FROM   (SELECT Group_No, Lob, COUNT(Sub_Group) 
           FROM   Subquery3 
           GROUP BY Group_No, Lob
           HAVING COUNT(Sub_Group) = 1) A 
   JOIN (SELECT Group_No, Sub_Group, Key, Lob
         FROM   Subquery3 
         WHERE  Sub_Group LIKE '0000%') B 
   ON A.Group_No = B.Group_No
   AND A.Lob = B.Lob

问题

如果我编辑最终查询以删除第二个内联视图并评估A内联视图的输出,我会得到0 个返回的行。我已经手动评估了每个单独子查询的记录,并且可以确认这是预期结果。

同样,如果我编辑最终查询以仅生成“B”内联视图的输出,我会得到6 个返回的行。同样,我手动评估了数据,这完全符合预期。

现在,当将这两个子集(内联视图A和内联视图B)连接在一起时,我希望最终查询结果为 0 行(因为完整集和空集之间的内部连接不会产生匹配项)。但是,当我如上所述使用内部连接运行整个查询时,我得到了 1158 行

我已经查看了执行计划,但没有任何问题:

执行计划 1 执行计划 2

问题

显然,我做了一些事情来混淆 Oracle 优化器,并且更新的查询计划正在撤回与我提交的查询完全不同的查询。我最好的猜测是,所有这些临时视图都在同一个查询中浮动,我混淆了 Oracle 以评估它所依赖的某个集合之前的某些集合。

直到今天,我一直无法在WITH声明周围找到官方的 Oracle 文档,因此我对评估子查询的顺序从未完全有信心。我在搜索 SO(现在找不到)时确实注意到有人提到因子子查询不能引用另一个因子查询。我以前从不知道这是真的,但上面奇怪的输出让我想知道我之前是否只是幸运地使用了这个查询?

谁能解释我看到的行为?我是否试图用这个查询计划做一些明显不正确的事情?或者,是否有可能在 11g 和 12c 之间发生了一些变化,这可以解释为什么这个查询的行为可能已经改变了?

4

1 回答 1

2

这听起来像是 Oracle 中的“错误结果”错误。这些错误通常非常特定于您使用的版本和功能。您发布的查询或执行计划没有明显错误。

您有两种处理方式:

  1. 尝试找到确切的错误。 您对公用表表达式所做的事情看起来不错。在某些情况下,您的查询在技术上是无效的,您在一个版本中获得“幸运”并且它可以工作,而当您升级时它会失败。但是当这种情况发生时,新版本通常会抛出错误,而不是返回错误的结果。您正在使用的一些非常奇怪的特定功能组合可能会导致问题。要找到真正的问题,您需要大量简化查询,直到您可以做出最小的更改并看到问题出现和消失。您还需要删除所有对象并仅使用DUAL. 此过程可能需要数小时。最后,当您只剩下几行代码时,要么将它们发布在这里,要么查看 Oracle 支持,
  2. 避免错误。 即使您完成了上述步骤,也可能无法修复。有时最好的解决方法是做一些不同的事情。深入了解每个问题是件好事,但你并不总是有时间。相反,请尝试以语法不同但逻辑等效的方式重新编写查询。删除部分或全部公用表表达式,甚至可能重复一些 SQL。但一定要留下评论,警告未来的程序员为什么你会以一种奇怪的方式做事。
于 2016-10-29T17:08:33.800 回答