Oracle 12c 以一种奇怪的方式解释 SQL(内部查询)

Oracle 12c interprets SQL in a strange way (Inner Query)

我们最近将 Oracle 数据库从 10g 迁移到了 12c (12.1.0.1.0)。在考虑了一些查询的问题后,我们决定进一步清理数据库并删除所有不需要的对象。
因此,我编写了一个查询,用于在数据库 DDL 中搜索要显示的特定文本,其中使用了特定的视图或函数。

SELECT 
  object_name, object_type, DBMS_METADATA.GET_DDL(object_type, object_name) as ddl_txt 
FROM user_objects 
WHERE object_type IN ( 'FUNCTION', 'VIEW', 'PROCEDURE', 'TRIGGER') 
  AND UPPER( DBMS_METADATA.GET_DDL(object_type, object_name) ) LIKE upper('%myFunction%')

这会导致以下异常:

ORA-31600: invalid input value TYPE BODY for parameter OBJECT_TYPE in function GET_DDL
ORA-06512: at "SYS.DBMS_METADATA", line 5746
ORA-06512: at "SYS.DBMS_METADATA", line 8333
ORA-06512: at line 1
31600. 00000 -  "invalid input value %s for parameter %s in function %s"
*Cause:    A NULL or invalid value was supplied for the parameter.
*Action:   Correct the input value and try the call again.

发生异常是因为我们的数据库中有 'Body Type' 个对象,但它们没有提供带有 DBMS_METADATA.GET_DDL() 的 ddl。 运行 下面的查询产生了与初始查询完全相同的异常。

select dbms_metadata.get_ddl('TYPE BODY', 'myBodyStringType') from dual

所以,我尝试创建一个内部列表,首先通过重写我的查询将所有用户对象的列表减少到我真正关心的列表:

select
  lst.*,
  DBMS_METADATA.GET_DDL(lst.object_type, lst.object_name) as ddl_txt 
from (
      SELECT 
        object_name, object_type
      FROM user_objects 
      WHERE object_type IN ( 'FUNCTION', 'VIEW', 'PROCEDURE', 'TRIGGER') 
) lst
where upper(DBMS_METADATA.GET_DDL(lst.object_type, lst.object_name)) like upper('%myFunction%')

有趣的是,它引发了与上面所示相同的异常。我不明白为什么会这样。

我希望 Oracle 首先创建内部列表并仅使用剩余值使用 DBMS_METADATA.GET_DLL() 函数,因为相同的值将导致异常。为什么 Oracle 在这里做其他事情?

为了解决那个特定问题,我必须在内部查询中添加一个 ORDER BY,这对我来说很愚蠢。为什么我必须强制 Oracle 首先使用 ORDER BY 创建内部查询?

select
  lst.*,
  DBMS_METADATA.GET_DDL(lst.object_type, lst.object_name) as ddl_txt 
from (
      SELECT 
        object_name, object_type
      FROM user_objects 
      WHERE object_type IN ( 'FUNCTION', 'VIEW', 'PROCEDURE', 'TRIGGER')
      ORDER BY ROWNUM ASC
) lst
where upper(DBMS_METADATA.GET_DDL(lst.object_type, lst.object_name)) like upper('%myFunction%')

提前感谢您解释为什么会这样? - 我记得,后来的查询 运行 在 Oracle 10g 上没有任何问题。
(我担心在其他进行计算的报告中也会出现相同的行为,而这种行为可能会导致错误!)。

很可能是谓词推送(抱歉,我找不到简单的解释)

这不是先运行内部记录集再计算余数。它正在将外部推入内部派生 table。查询计划肯定会告诉你。

通过使用 ROWNUM,您强制它首先评估内部记录集。不是 ORDER BY 而是 ROWNUM 这样做的。除了 ORDER BY 你也可以做 AND ROWNUM > 0 它会做同样的事情,因为它必须先计算每一行才能计算 ROWNUM 表达式。

这是一个错误。 Oracle 支持刚刚向我确认异常是由于 Oracle 版本 12.1.0 中的一个错误而发生的。1 而已。

有两个选项可供选择:
1) 更新到Oracle版本12.1.0.2 修复bug.
2) 等待几周,等待 Oracle 即将开始开发的补丁。该补丁将在 Oracle 版本 12.1.0.1.
中修复此问题
我们没有决定采用哪个选项,但我非常有信心一个或另一个会起作用,因为 Oracle 支持确实重现了我的问题。