Oracle 12c Subquery Factoring Inline View现在有不好的计划吗?

时间:2016-10-28 18:59:47

标签: sql oracle inline-view query-planner subquery-factoring

更新11/2

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

作为一种解决方法,我能够对查询进行细微更改,以便检索预期结果。具体来说,我将Subquery1Subquery2合并,我将Subquery1中的一些谓词从WHERE子句移到了JOIN(他们更适合的地方)。此更改编辑了我的执行计划(它的效率略低于之前列出的效率)但足以解决原始问题。

原帖

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

背景

我有一个Oracle查询,我很久以前投入生产,最近在从11g升级到12c后不久产生了预期结果。对于我(以及我的生产支持团队)的知识,这个查询在此之前已经运行了一年多。

详情

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

我有3个表Table1Table2Table3Table1是由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行

我已经审查了执行计划,但没有任何事情发生在我身上:

Execution Plan 1 Execution Plan 2

问题

显然,我已经做了一些事情来混淆Oracle Optimizer,而更新的查询计划正在拉回一个与我提交的查询截然不同的查询。我最好的猜测是,所有这些临时视图都在同一个查询中浮动,我让Oracle混淆了在依赖它之前评估一些集合。

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

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

1 个答案:

答案 0 :(得分:2)

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

您有两种处理方法:

  1. 尝试找到准确的错误。您使用公用表表达式所做的事情看起来很好。在极少数情况下,您的查询在技术上无效,您会幸运地获得"幸运"在一个版本中它可以工作,当你升级它失败。但是当发生这种情况时,新版本通常会抛出错误,而不会返回错误的结果。可能有一些非常奇怪的,特定的功能组合,您正在使用导致问题的功能。要找到真正的问题,您需要大规模简化查询,直到您可以进行尽可能小的更改并看到问题出现和消失。您还希望删除所有对象,并仅使用DUAL。此过程可能需要数小时。最后,当您只剩下几行代码时,请在此处发布,查看Oracle支持或创建服务请求。
  2. 避免错误。即使您完成上述步骤,也可能无法修复。有时,最好的解决方法是采取不同的做法。能够深入了解每个问题,但你总是没有时间,这很好。相反,尝试以语法不同但逻辑上等效的方式重写查询。删除部分或全部公用表表达式,甚至可能重复一些SQL。但请务必发表评论,警告未来的程序员,为什么你会以一种奇怪的方式做事。