【发布时间】:2016-10-28 18:59:47
【问题描述】:
11 月 2 日更新
经过一些额外的故障排除后,我的团队能够将这个 Oracle 错误直接与查询停止工作前一天晚上在 12c 数据库上所做的参数更改联系起来。在遇到与此数据库相关的应用程序的一些性能问题后,我的团队让我们的 DBA 将 OPTIMIZER_FEATURES_ENABLE 参数从 12.1.02 更改为 11.2.0.4。这解决了问题应用程序的性能问题,但导致了我上面描述的错误。为了验证,我已经能够通过更改此参数在单独的环境中复制同样的问题。我的 DBA 已向 Oracle 提交了一张票,以查看此问题。
作为一种解决方法,我可以对我的查询稍作更改以检索预期结果。具体来说,我将Subquery1 与Subquery2 组合在一起,并将Subquery1 中的一些谓词从WHERE 子句移到JOIN (它们更适合归属)。此更改编辑了我的执行计划(它的效率略低于之前列出的内容),但足以解决最初的问题。
原帖
首先,让我为这个问题的含糊之处道歉,但我正在处理一个机密的金融系统,所以我不得不隐藏某些实施细节。
背景
我有一个很久以前投入生产的Oracle 查询,在从11g 升级到12c 之后巧合地最近停止产生预期结果。据我(和我的生产支持团队)所知,此查询在此之前已经运行了一年多。
详情
查询过于复杂且效率不高,但这在很大程度上是因为我正在处理非规范化表(历史上以大型机建模)和来自上游系统的不良数据输入。为了处理复杂的业务情况,我利用了多个级别的子查询因子(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 行!
我已经查看了执行计划,但没有任何问题:
问题
很明显,我做了一些事情来混淆 Oracle 优化器,并且更新后的查询计划正在拉回一个与我提交的查询完全不同的查询。我最好的猜测是,所有这些临时视图都在同一个查询中浮动,我混淆了 Oracle 以评估它所依赖的某个集合之前的某些集合。
直到今天,我一直无法在 WITH 语句周围找到官方 Oracle 文档,因此我对评估子查询的顺序从未完全有信心。我在搜索 SO(现在找不到)时确实注意到有人提到一个因式子查询不能引用另一个因式查询。我以前从不知道这是真的,但上面奇怪的输出让我想知道我之前是否只是幸运地使用了这个查询?
谁能解释我看到的行为?我是否试图用这个查询计划做一些明显不正确的事情?或者,是否有任何可能在 11g 和 12c 之间发生了一些变化,这可以解释为什么这个查询的行为可能发生了变化?
【问题讨论】:
-
嗨,- 绝对是一个因式子查询可以引用另一个子查询(总是在它之前定义),我一直在非常复杂的组合中使用它,并且在 11.2 和 12.1 中它永远不会失败。然后 - Oracle 版本之间的许多事情可能会有所不同;以前未强制执行的规则现在强制执行,或者他们改进了实现,但您遇到了一个案例,他们没有测试他们在哪里破坏了某些东西,这种情况一直在发生。您可以考虑在 OTN 上发布相同的内容,那里有一些优化专家,他们根本不会访问这么多。祝你好运!
-
或者 - 实际上,哇,现在我阅读了完整的问题 - 您不仅有效率问题,还有逻辑问题。这更有可能揭示代码中的错误,而不是 Oracle 破坏了某些东西。由于出于明显的业务保护原因您无法共享代码,因此很难获得帮助。您是否能够在确认问题仍然存在的同时按顺序简化查询?尝试隔离问题 - 它很可能是您之前不知道的代码中的错误。
-
@mathguy 感谢您对相关因子子查询的确认。我一开始以为我要疯了。我更有信心在 Oracle 中发现了我构建此查询的方式的一些错误,因此我将开始尝试重构,看看我是否无法隔离它。
标签: sql oracle inline-view query-planner subquery-factoring