戴安娜是谁,她为啥不让我的数据库对象编译?

Posted

技术标签:

【中文标题】戴安娜是谁,她为啥不让我的数据库对象编译?【英文标题】:Who is diana, and why won't she let my database objects compile?戴安娜是谁,她为什么不让我的数据库对象编译? 【发布时间】:2011-12-07 13:22:33 【问题描述】:

好的,所以问题的标题有点半开玩笑,但问题已经足够严重了。有时,在编译架构中的对象或导入转储文件时,我会看到以下错误消息:

ORA-04028: cannot generate diana for object SCOTT.VW_EMP

这实际上意味着什么,我该如何避免?

【问题讨论】:

论坛dbasupport.com/forums/archive/index.php/t-36201.html 说“DIANA 代表 Ada 的描述性中间属性表示法”。听起来像是在后台从您的代码中生成了一些东西,并且出现了一些问题:-) 我在 Google 上看到的大部分链接都与锁定冲突有关。如果有东西锁定了该对象,可能值得研究。 @LasseV.Karlsen - 但是在导入时会发生这种情况吗? impdp 何时或是否锁定对象超出了我的控制范围...... 我不知道,我只是发现这个问题对谷歌来说足够有趣,我不是甲骨文专家(或用户)。 +1:一个很棒的标题,一个奇怪的问题,一个得到明确答案的好东西。 【参考方案1】:

此处相关:PL/SQL、包大小、解析树节点、代码行数。

Diana 是 Oracle 的接口定义语言,用于将数据库表的结构和 PL/SQL 程序单元的逻辑表示为属性树。

解析树节点的数量存在内部限制。编译器版本设置最大代码行数。

因此,请检查 PL/SQL 逻辑的大小和代码行数。可能不可能,甚至没有必要知道您的版本可以处理的实际限制。

一旦您知道合适的包裹尺寸,问题就解决了一半。

当你解决了另一半时也告诉我们,谢谢。

【讨论】:

schurik,调试符号表溢出可能是作为即将发生灾难的警告发生的,也许?我们应该停止治疗症状吗?如果您关闭调试并进一步增加包大小,gaasp,戴安娜会来电话吗?【参考方案2】:

您能否分享您遇到错误的代码的 sn-p。

这里的描述可能会帮助您理解为什么会出现错误: PL/SQL 基于称为 ADA 的编程语言。因此,当您在 PL/SQL 中编写 pgram 时,它会为 Ada 生成一个“DIANA”-> Descriptive Intermediate Attributed Notation,这是一种树形结构的中间语言。编译器和其他工具在内部使用 DIANA。

它是如何工作的: 1) 编译时将PL/SQL源代码翻译成系统代码,生成对应的DIANA。

2)子程序或包的 DIANA 和系统代码都存储在数据库中。

3)在运行时,它们被加载到共享内存池中。

4)DIANA用于编译依赖子程序;更具体地说,检查/验证子程序是否仍然有效。这是必需的,因为我们知道子程序可以使用数据库对象,例如表、视图、同义词或其他存储过程。下次运行程序时,对象可能已更改/删除/丢弃。 例如:有人可能删除了表,存储的过程或函数签名可能已更改。

5) 使用 DIANA 完成验证后,系统代码就会运行。

对您的程序的限制:

在共享内存池中,一个包规范、ADT 规范、独立子程序或匿名块被限制为 67108864 (2**26) 个 DIANA 节点,这些节点对应于标识符、关键字、运算符等令牌。这允许大约 6,000,000 行代码,除非您超出 PL/SQL 编译器施加的限制

你可以参考这个链接: http://docs.oracle.com/cd/E14072_01/appdev.112/e10472/limits.htm#

现在来解决您的问题 - ora-04028:

可能是以下原因之一:

1)当您从调用函数的视图中选择时,会出现一些错误,该视图也从同一视图中选择

2) 数据库服务器、客户端或 rman 目录的版本不合适。你需要打补丁

3)您尝试将 Oracle 11g 实例注册到 10.2.0.1 RMAN 目录。为了成功,请将目录升级到至少版本 10.2.0.3

【讨论】:

【参考方案3】:

根据Oracle documentation,

PL/SQL 基于编程语言 Ada。 PL/SQL 使用 Ada 的描述性中间属性表示法 (DIANA) 的变体,这是一种树形结构的中间语言。 它是使用称为接口定义语言 (IDL) 的元表示法定义的。 编译器和其他工具在内部使用 DIANA。

在编译时,PL/SQL 源代码被翻译成机器可读的 m 代码。 过程或包的 DIANA 和 m 代码都存储在数据库中。 在运行时,它们被加载到共享内存池中。 DIANA 用于编译相关程序; m代码被简单地执行。

很遗憾,您无法根据解析的大小估计 DIANA 节点的数量。 具有相同解析大小的两个程序单元可能需要 1500 和 2000 个 DIANA 节点, 分别是因为,例如,第二个单元包含更复杂的 SQL 语句。

Ask tom says

有关 DIANA 节点计算的更多信息,请阅读本书“Ada-Europe '93: 12th Ada-Europe International Conference, "Ada Sans Frontieres", Paris, France, June 14-18, 1993. Proceedings"强>

以下支持说明很好地涵盖了这个主题...

Article-ID:         <Note:62603.1>
Folder:             PLSQL
Topic:              General Information Articles
Title:              'PLS-123 Program too Large' - Size Limitations on PLSQL 
                    Packages
Document-Type:      BULLETIN
Impact:             MEDIUM
Skill-Level:        NOVICE
Server-Version:     07 to 08
Updated-Date:       13-JUN-2000 17:41:01
References:         

概述

本文包含有关 PL/SQL 包大小限制的信息。当限制是 到达时,您会收到以下错误:

PLS-123 Program too large

PL/SQL 包的大小限制

在 8.1.3 之前的版本中,大型程序会导致 PLS-123 错误。这发生了 因为编译器的真正限制;不是由于错误。

在编译 PL/SQL 单元时,编译器会构建解析树。最大尺寸 PL/SQL 单元由解析树的大小决定。最大戴安娜节点数 存在于这棵树中。

到 7.3,您可以有 2 * * 14 (16K) 个 diana 节点,从 8.0 到 8.1.3,2 * * 15 (32K) 戴安娜节点是允许的。在 8.1.3 中,此限制已放宽,因此您现在可以 此树中有 2 * * 26(即 64M)个戴安娜节点,用于包和类型主体。

源代码限制

虽然没有简单的方法来转换源代码行数的限制,但我们观察到每行源代码大约有 5 到 10 个节点。在 8.1.3 之前,编译器最多可以干净地编译大约 3000 行代码。

从 8.1.3 开始,放宽了对包体和类型体的限制,现在可以有大约 6,000,000 行代码。

注意:此新限制仅适用于包体和类型体。此外,您现在可能会在达到此特定编译器限制之前开始达到其他一些编译器限制。

就源代码大小而言,假设标记(标识符、运算符、函数等)平均有四个字符长。那么,最大值将是:

   Up to 7.3:         4 * (2 * * 14)=64K
   From 8.0 to 8.1.3: 4 * (2 * * 15)=128K
   With 8.1.3:        4 * (2 * * 25)=256M

这是一个粗略的估计。如果您的代码有很多空格、长标识符等,您可以 最终得到比这更大的源代码。您可能还会得到更小的源代码 如果您的来源使用非常短的标识符等,则比这更多。

注意这是每个程序单元,所以包体最有可能遇到这个 限制。

如何检查包裹的当前大小

要检查包的大小,您可以使用的最接近的相关数字是 PARSED_SIZE 数据字典视图 USER_OBJECT_SIZE。该值提供了 DIANA 的大小 存储在 SYS.IDL_xxx$ 表中的字节,而不是共享池中的大小。

PL/SQL 代码的 DIANA 部分(在编译期间使用)的大小在 共享池比它在系统表中。

例如,当 PARSED_SIZE 在 USER_OBJECT_SIZE 不超过 50K。

对于一个包,解析后的大小或 DIANA 的大小仅对整体有意义 对象,不单独为规范和正文。

如果您为包选择 parsed_size,您将收到单独的源代码和代码大小 规范和正文,但只有整个对象的有意义的解析大小 是在包装规范的行上输出。 parsed_size 输出 0 就行为包体。

以下示例演示了这种行为:

CREATE OR REPLACE PACKAGE example AS  
  PROCEDURE dummy1;  
END example;  
/  
CREATE OR REPLACE PACKAGE BODY example AS  
  PROCEDURE dummy1 IS  
  BEGIN  
    NULL;  
  END;  
END;  
/  

SQL> start t1.sql;  

Package created.  


Package body created.  

SQL> select parsed_size from user_object_size where name='EXAMPLE';  


PARSED_SIZE  
-----------  
        185  
          0  


SQL> select * from user_object_size where name='EXAMPLE';  

  .....

Oracle 将 DIANA 和 MCODE 都存储在数据库中。 MCODE 是实际运行的代码, 而特定图书馆单元 X 的 DIANA 包含需要的信息 使用库单元 X 编译过程。

以下是几个注意事项:

a) DIANA 以 IDL 表示。 IDL 的线性版本存储在磁盘上。这 实际的解析树被建立并存储在共享池中。这就是为什么大小 共享池中的 DIANA 通常比磁盘上的大。

b) 仅当您创建时,共享池中才需要调用过程的 DIANA 程序。在生产系统中,共享池中不需要 DIANA (但仅适用于 MCODE)。

c) 从 7.2 版开始,包体的 DIANA 被丢弃,不被使用, 并且不存储在数据库中。这就是为什么 PARSED_SIZE(即 DIANA 的大小) 包体为 0。

因此,应始终定义大型过程和函数 包内!

一个包存储在数据库中的 DIANA 中,就像一个过程一样。一个包可以用来 然而,打破依赖链,也许会让它消失。我相信所有 生产(真实)代码应该在一个包中,而不是在一个独立的过程或函数中。

【讨论】:

【参考方案4】:

Oracle 10.2.5 中存在一个错误(未发布的错误 9342254;参见文档 ID 1505092.1),Oracle 11.1 及更高版本已针对该错误进行了修复;我认为这可能是这里的问题。

您可以通过刷新共享池来解决它:

ALTER SYSTEM FLUSH SHARED_POOL

注意。这是一个非常古老的问题,但我把它留在这里以防其他人遇到这个问题。 Nineside 和我实际上在同一家公司工作,并且是独立遇到的。

【讨论】:

【参考方案5】:

我在调试模式下编译大型包时遇到了类似的问题。 如果调试信息的大小超出了编译器对调试符号表大小的限制,就会发生这种情况。 您可以使用

关闭调试模式
alter session set plsql_debug=false; 

或整个数据库:

alter system set plsql_debug=false;

【讨论】:

impdp 在导入对象时是否使用调试模式?

以上是关于戴安娜是谁,她为啥不让我的数据库对象编译?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 OpenDDS 无法编译?

为啥 xamarin 突然不让我部署到 iOS 设备

为啥我的Java应用程序每次编译完数据库包后都需要重启?

为啥我的数据库对象没有显示记录集?

为啥 Flutter 编译器告诉我我的应用程序不存在?

为啥 forEach 函数不让我返回一个对象,甚至只是将它从函数中传递出去?