Oracle 数据库 10g 版本 1 中的 PL/SQL 纯编译 (NCOMP)

来源:互联网 发布:指定flashfxp端口 编辑:程序博客网 时间:2024/05/16 10:53
Oracle 数据库 10g 版本 1 中的 PL/SQL 纯编译 (NCOMP)

2004 年 9 月 4 日更新

 

什么是纯编译?
如何实现 PL/SQL 纯编译?
Oracle 数据库 10g 有什么新特性?
什么对象可以进行 PL/SQL 纯编译?
共享库 (DLL) 的命名惯例是什么?
共享的动态链接库是否可以移植?
在部署端是否需要 C 编译环境?
哪些 Oracle 参数与纯编译相关?
plsql_native_library_dir 参数
plsql_native_library_subdir_count 参数
plsql_code_type 参数
$ORACLE_HOME/plsql/spnc_commands 文件的格式
纯编译生成的共享库存储在哪个字典表中?
当删除一个“纯编译”单元时,文件系统上的共享库将发生什么?
如何更改 plsql_native_library_dir?
是否还有其他场合需要手动删除共享库?
如果误删除了一个共享库该怎么办?
甲骨文公司是否建议混合使用纯编译单元和解释单元?
在操作系统升级时,是否需要重新生成纯编译的共享库?
在应用程序部署期间是否能够使用纯编译模式来节省时间(通过提供预先生成的 NCOMP 共享库)?
纯编译测试:简单测试
将数据库中的所有 PL/SQL 单元进行纯编译

什么是纯编译?

您可以通过将 PL/SQL 模块(程序包、触发器、过程、函数和类型)编译成驻留在共享库中的纯代码来加速它们的运行。过程被转换成 C 代码,然后用一个 C 编译器进行编译,并与 Oracle 进程动态链接。

您可以将该技术用于随付的 Oracle 程序包以及您自己编写的过程。用这种方式编译的过程可以用于所有服务器环境,如共享服务器配置(以前称为多线程服务器)和 Oracle 真正应用集群。

使用了大量有代表性测试程序的性能实验(发布在 OTN 上)表明,在 Oracle 数据库 10g 中,纯 PL/SQL 程序的应用程序在编译时的速度与解释编译时的速度相比(其他保持不变),预计可以获得大约 1.05 到 2.4 倍的性能提高。提高的程度取决于程序的种类。

注意:许多 Oracle 提供的程序包(如 UTL_FILE、UTL_RAW、DBMS_LOB)已经用 C 实施,而仅使用 PL/SQL 来提供 API。这些程序包不大可能从纯编译中获得显著的性能提高。同样,仅调用 SQL 语句的 PL/SQL 程序单元也可能几乎得不到加速。不过,纯编译的 PL/SQL 往往至少和相应的解释代码一样快。编译的代码将与解释的代码执行相同的库调用,因此它们的行为是完全相同的。

返回页首


如何实现 PL/SQL 纯编译?

如果未使用纯编译,则将每个 PL/SQL 程序单元编译成一种中间形式的机器可读码 (MCode)。MCode 存储在数据库字典中,并在运行时进行解释。

使用 PL/SQL 纯编译,将 PL/SQL 程序编译成无需运行时解释的纯机器码,从而加快运行速度。

PL/SQL 使用命令文件 $ORACLE_HOME/plsql/spnc_commands 和支持的操作系统 C 编译器和链接器,将生成的 C 代码编译并链接到共享库中。共享库存储在数据字典中,这样便可将它们自动备份并防止它们被删除。这些共享库文件被复制到文件系统中,并在调用 PL/SQL 子程序时被加载和运行。如果在关闭数据库时从文件系统中删除了这些文件,或者如果您更改了这些库所在的目录,则自动重新提取这些文件。

返回页首


Oracle 数据库 10g 有什么新特性?

这个特性现在需要更少的设置和维护。

  • 不需要用相同的代码类型设置来编译程序包主体及其规范。例如,可以对程序包主体进行纯编译,而对程序包规范进行解释编译。
  • 经过纯编译的子程序存储在数据库中,并在需要的时候自动提取相应的共享库。对于备份共享库、清理原有共享库等事项,您无需操心。
  • 而且简化了纯编译的初始化参数和命令的设置。唯一需要的参数是 plsql_native_library_dir。不再使用与编译器、链接器和 make 实用程序相关的参数。$ORACLE_HOME/plsql/spnc_commands 命令文件用于进行纯编译。它包含了用于编译和链接的命令和选项,从而不再依赖于 make 实用程序。不再需要或支持 plsql_native_make_utilityplsql_native_make_file_name 参数,但仍须像在 9.0.1 版和 9.2.0 版中一样指定 plsql_native_library_dir。这将指定用于生成共享库(在共享库被复制到数据库中之前)的目录的完整路径。
  • 纯编译期间出现的所有错误都存储在 USER_ERRORS 字典视图中,可通过 SQL*Plus 命令 SHOW ERRORS 来查询。
  • 开启和关闭纯编译是由一个单独的参数 plsql_code_type 来控制的,而不是 plsql_compiler_flags 参数的几个选项之一,现在不建议使用后者。
  • RAC 支持:现在在没有集群(共享)文件系统的 RAC 环境中也支持 PL/SQL 纯编译。
  • 共享库清理:当删除(或在解释模式下重新编译)纯编译的 PL/SQL 模块时,现在将删除(在 plsql_native_library_dir 指定的位置下的)共享库的文件系统副本。在 RAC 配置中,将从所有实例中删除共享库。
  • 返回页首


    什么对象可以进行 PL/SQL 纯编译?

    任何存储的 PL/SQL 模块都可以进行纯编译。匿名的 PL/SQL 程序块不能进行纯编译。

    注意:Oracle 支持以下类型的存储 PL/SQL 模块:

    FUNCTIONPACKAGEPACKAGE BODYPROCEDURETRIGGERTYPETYPE BODY

    返回页首


    共享库 (DLL) 的命名惯例是什么?

    纯编译为每个单元创建一个共享库。例如,将为程序包规范和程序包主体分别创建一个共享库。以下是生成的一些名称:

    PKG__SCOTT__S__54682.soPKG__SCOTT__B__54683.so

    生成的名称一般包含单元名称、模式名称、对象类型和对象编号。不过,这是一个可能会变更的内部惯例,用户不应依赖这种文件名格式规范。

    文件名的扩展名在不同平台上可能不同。例如,在 Solaris 上共享库的后缀为 .so,而在 HP-UX 上共享库的后缀为 .sl

    返回页首

    共享的动态可链接库是否可以移植?

    不,绝对不行!共享库包含特定于平台的目标代码。

    注意:在解释方式下创建的 MCode 也是特定于平台的。

    返回页首


    在部署端是否需要 C 编译环境?

    是的。没有商量的余地。PL/SQL 单元可能需要在部署端进行编译,PL/SQL 纯编译依靠一个 C 编译器来生成目标(机器)代码。

    例如,各种操作(如向表中增加一列)可能导致与该表相关的 PL/SQL 单元的自动失效。对这种单元的后续访问将触发重新编译。在这种情况下,在纯编译模式下再次重新编译该单元需要 C 编译环境。

    另一种情况是需要在部署数据库上应用补丁。可能需要在部署环境中重新加载和编译个别程序包。

    返回页首


    哪些 Oracle 参数与纯编译相关?

    • plsql_native_library_dir
    • plsql_native_library_subdir_count
    • plsql_code_type
    返回页首

    plsql_native_library_dir 参数

    这个参数指定保存共享库 (DLL) 的 OS 副本的目录位置。

    当对一个模块进行纯编译时,将在这个位置创建共享库,然后将其复制到数据库字典表 (ncomp_dll$) 中。虽然共享库的主副本驻留在数据库中,但还将共享对象在文件系统中进行了物化,以便能够动态地将它们加载到 Oracle 的地址空间中。

    注释 1:用户 (DBA) 决不能在系统启动并运行时从 plsql_native_library_dir 中手动删除共享库,因为这些 DLL 可能被映射到了 Oracle 进程上。只有在系统关闭的时候才能安全地删除共享库的 OS 副本。

    注释 2:在 RAC 配置中,必须在每个实例中设置这个参数。不要求各实例拥有共享文件系统。在每个实例上,必须将 plsql_native_library_dir 设置为指向一个实例本地目录。或者,如果 RAC 配置支持共享(集群)文件系统,您可以将(共享文件系统上的)一个公共的目录用于所有实例。

    注释 3:您必须创建这个目录。Oracle 不会自动为您创建这个目录。

    注释 4:甲骨文公司在单实例或 RAC 配置中都不为 plsql_native_library_dir 提供 NFS 挂载目录支持。这是因为 NFS 在写或删除文件时会导致一些不可预测的时序问题。

    返回页首


    plsql_native_library_subdir_count 参数

    一些文件系统可能无法在单个目录中处理大量的文件;您可能需要在 plsql_native_library_dir 指定的目录下创建子目录来存储纯编译生成的共享库。

    如果您使用的是生产品质的文件系统(例如 Veritas),那么您可能无需创建子目录。然而,如果您使用的是 vanilla 文件系统,那么它可能无法在单个目录中轻松地处理大量的文件。对于拥有大约 70,000 个 PL/SQL 对象的 Oracle 应用程序,在使用 vanilla 文件系统时,我们使用了大约 500 个子目录。

    这个参数的默认值是 0。为了指示 Oracle 将共享库分配到不同的子目录中,而不是将所有共享库存储在 plsql_native_library_dir 指定的单个目录中,请将 plsql_native_library_subdir_count 参数设为您要创建的子目录数。

    例如,要使用 500 个子目录,则将以下行添加到您的初始化参数文件中:

    plsql_native_library_subdir_count=500

    然后您必须创建 500 个子目录(在 plsql_native_library_dir 参数指定的目录下),目录名称即为 d0、d1、d2、..、d498、d499

    返回页首


    plsql_code_type 参数

    plsql_code_type 参数决定对 PL/SQL 代码是进行纯编译还是解释。默认设置是 INTERPRETED。要启用 PL/SQL 纯编译,请将 plsql_code_type 的值设为 NATIVE。如果您想以 NATIVE 方式编译整个数据库,那么甲骨文公司建议您在系统级或在初始化参数文件中设置 plsql_code_type

    使用以下语法设置该参数:

    • 对于纯编译模式:
      alter session set plsql_code_type='NATIVE'
      或者,
      alter system set plsql_code_type='NATIVE'
    • 对于解释模式:
      alter session set plsql_code_type='INTERPRETED'
      或者,
      alter system set plsql_code_type='INTERPRETED'

    返回页首


    spnc_commands 文件的格式

    $ORACLE_HOME/plsql 目录中的 spnc_commands 文件包含了编译和链接各个程序的命令模板。一些特殊的名称(如 %(src))被预先定义,并用相应的文件名进行了替换。变量 $(ORACLE_HOME) 也自动被 Oracle 主目录的位置替换。您可以包含命令行(以 # 字符开始)。该文件包含解释所有特殊符号的注释。

    spnc_commands 文件根据特定的操作系统为 C 编译器包含了一个预先定义的路径。(每种操作系统支持一种特定的编译器。)在大多数情况下,您不需要更改这个路径,但如果系统管理员将编译器安装在了另一个位置,您可能就需要更改它了。

    这种方法意味着(与 9.0.1 版和 9.2.0 版不同)这里与 make 实用程序不存在依赖关系。

    返回页首


    纯编译生成的共享库存储在哪个字典表中?

    纯编译生成的共享库被作为 BLOB 存储在数据库中的 ncomp_dll$ 字典表中。

    SQL> connect / as sysdba;Connected.SQL> describe ncomp_dll$;Name        Null?Type ------------   --------------    -------- OBJ#        NOT NULL          NUMBERVERSION          NUMBERDLL          BLOBDLLNAME          RAW(1024)

    返回页首


    当删除一个“纯编译”单元时,文件系统上的共享库将发生什么?

    直到 9.2.0,未发生任何事情。不会对共享库进行垃圾收集。

    在 10.1.0 版中,当删除或在解释模式下重新编译一个纯编译的单元时,将从 ncomp_dll$ 字典表以及从 plsql_native_library_dir 参数指定的文件系统位置中删除该共享库。在 RAC 配置的情况下,将从每个实例的 plsql_native_library_dir 位置中删除该共享库。

    返回页首


    如何更改 plsql_native_library_dir?

    如果您需要更改该参数的值,建议采取以下步骤:

    1. 关闭数据库实例
    2. 将初始化参数文件中的 plsql_native_library_dir 设置更改为指向新的位置。
    3. 重新启动数据库实例。Oracle 将根据需要自动将共享库提取到这个新的位置中。

    注释 1:虽然可以通过 alter system..命令来更改这个参数,但 Oracle 不建议这么做。

    注释 2:一旦执行了上述步骤,就可以安全地删除与 plsql_native_library_dir 先前的设置对应的原有目录了。Oracle 不会 自动从原有位置删除共享库。

    返回页首


    是否还有其他场合需要手动删除共享库?

    没有。

    唯一的例外是当您想修改 plsql_native_library_dir 的设置的时候。请按照先前所述步骤更改 plsql_native_library_dir。然后就可以从原有位置删除共享库了。

    返回页首


    如果误删除了一个共享库该怎么办?

    这可能导致非预期的内部错误和问题。建议的补救办法是关闭然后重新启动实例。Oracle 将根据需要自动从 ncomp_dll$ 字典表中提取共享库。

    返回页首


    甲骨文公司是否建议混合使用纯编译单元和解释单元?

    虽然支持混合使用,并且决不会导致错误的行为,但当纯编译单元调用解释单元时,需要付出一定代价。如果纯编译单元频繁调用解释单元,那么您可能牺牲一些潜在的性能改善。

    如果将所有模块纯编译成共享库的时间是个问题,那么一种选择是考虑将程序包和类型规范在解释模式下进行编译,而将所有其他类型的 PL/SQL 单元(程序包主体、类型主体、过程、函数和触发器)在纯编译模式下进行编译。因为规范一般没有太多可执行代码,因此就运行时性能而言您不会有太大损失。

    返回页首


    在操作系统升级时,是否需要重新生成纯编译的共享库?

    假设您已经确定甲骨文支持这种类型的 OS 升级,而无需重新生成普通的 Oracle 可执行文件,那么 PL/SQL 纯编译产生的共享库也将可用,而无需重新生成。

    返回页首


    在应用程序部署期间是否能够使用纯编译模式来节省时间(通过提供预先生成的 NCOMP 共享库)?

    不能!即使共享库是在与最终部署环境相同的平台上生成的,您也无法这么做。您也无法在解释模式下利用 MCode 这么做。

    其原因与编译模式无关。基于 PL/SQL 的应用程序在数据库中的安装需要在数据库中加载和编译 PL/SQL 模块,以便可以正确解析所有的外部引用。

    返回页首


    纯编译测试:简单测试

    1. 创建一个目录,用于存储纯编译生成的共享库,并在初始化参数文件中将 plsql_native_library_dir 参数设置为指向该目录路径。例如,您需要在初始化参数文件中添加如下内容:
      plsql_native_library_dir=/home/kmuthukk/oracle10g/dbs/ncomp_libraries

       

    2. 还可以在初始化参数文件中设置 plsql_native_library_subdir_count 并创建子目录。
    3. 确保 spnc_commands 文件中使用的 C 编译器 — 以及链接器(如果适用) — 的 OS 路径是正确的。
    4. 系统参数完整性检查: 必须指定 plsql_native_library_dirplsql_native_library_subdir_count 是可选的,可以保留为 0(如果您不打算使用基于子目录的模式)。最好在初始化参数文件中指定这些参数。
      SQL> show parameters plsql_nativeNAME     TYPE VALUE------------------------------------ ----------- ------------------------------plsql_native_library_dir     string /home/kmuthukk/oracle10g/dbs/ncomp_librariesplsql_native_library_subdir_count    integer 0
    5. 对 PL/SQL 模块进行纯编译
      1. 要在纯编译模式下加载和编译新的模块,必须将 plsql_code_type 参数设为 NATIVE。

        例如,尝试在 SQL*Plus 中执行以下操作:

        connect scott/tigeralter session set plsql_code_type='NATIVE';create or replace procedure my_test isbegindbms_output.put_line('hello world');end;/show errors;set serveroutput on;execute my_test;

        验证步骤

        1. 看一下 plsql_native_library_dir 指定的位置。应找到一个与 MY_TEST 过程相对应的新的共享库。在 Solaris 上,DLL 可能有一个类似 MY_TEST__SCOTT__P__54765.so 的名称。

          [要阅读有关共享库命名惯例的更多信息,请点击此处。]

           

        2. 此外,通过执行以下查询,确保该模块的 plsql_code_type 设置的确为 NATIVE:
          select name, type, plsql_code_type from user_plsql_object_settings where name = 'MY_TEST';

         

      2. 如果您想手动地对特定的已经加载的模块进行编译,那么您可以使用 alter ... compile .. 语句。

        假定您有一个程序包 MYPKG,其规范和主体是用解释方式编译的。现在,如果您只想对其主体进行纯编译,那么可以执行以下命令:

        alter package MYPKG compile body plsql_code_type=native reuse settings   

        上面的 reuse settings 子句指示编译器应当保留该单元所有以前的设置 — 被显式覆盖的设置(如在上述示例中设定的 plsql_code_type 的设置)除外。

        如果从上面的语句中删除了 body 子句,如:

        alter package MYPKG compile plsql_code_type=native reuse settings

        ... 那么规范和主体都将在纯编译模式下重新编译。不过请注意,重新编译规范将造成依赖于该规范的其他模块失效。

    返回页首


    将数据库中的所有 PL/SQL 单元进行纯编译

    在试图将数据库中的所有 PL/SQL 单元进行纯编译之前,在一个简单的测试案例上试验一下(如上一部分所述)。这将帮助确保您的纯编译设置是正确的。

    1. 操作系统文件描述符限制

      $ORACLE_HOME/rdbms/admin 目录下的两个 SQL*Plus 脚本(dbmsupgnv.sqlutlrp.sql)用来在纯编译模式下重新编译所有的 PL/SQL 模块。它们使用并行作业(取决于可用的 CPU 的数量)。在这种情况下,许多作业同时生成 C 文件并试图编译它们。因此不将文件描述符的最大数的 OS 限制设得过低非常重要。

      例如,在我的 Solaris 计算机上:

      % ulimit -atime(seconds)        unlimitedfile(blocks)         unlimiteddata(kbytes)         2097148stack(kbytes)        8192coredump(blocks)     3nofiles(descriptors) 64vmemory(kbytes)      unlimited

      注意描述符的最大数(值为 64)。这在生产环境中太少了,因为有许多作业要进行并行纯编译。您可能想查看您计算机上的限制,并将其提高。例如:

      在 Solaris 上,需要编辑 /etc/system 文件,使之包含:

      set rlim_fd_max=4096set rlim_fd_cur=1024

      在 HP-UX 上,相应的参数位于 /stand/system 文件中。

      maxfiles        2048 maxfiles_lim    2048 

       

    2. 系统表空间

      因为 DLLs 的主副本存储在字典表中,因此您可能需要比以前更多的 SYSTEM 表空间。如果您遇到了与 SYSTEM 表空间的空间限制相关的错误,那么您将需要执行如下操作:

      alter tablespace systemadd datafile '/home/kmuthukk/oracle10g/dbs/mydata10.dbf'size 500 m;

      .. 或在数据文件上设置 autoextend

       

    3. 以纯编译模式重新编译所有的模块(dbmsupgnv.sqlutlrp.sql
      1. 关闭所有的应用程序服务(包括 Forms Processe、Web Server、Reports Server 和 Concurrent Manager Server)。在关闭所有的应用程序服务之后,确保中断了所有与数据库的连接。

         

      2. 关闭数据库的 TNS 监听器,以确保不会创建新的连接。

         

      3. 关闭数据库(以正常模式或即时模式)。

         

      4. 确定您已在初始化参数文件中设置了 plsql_native_library_dir。如果没有,则请查看上一部分所述的步骤。

         

      5. 在初始化参数文件中将 plsql_code_type 设为 NATIVE。
        plsql_code_type=NATIVE

         

      6. UPGRADE 模式下启动数据库(使用 STARTUP UPGRADE 或 ALTER DATABASE OPEN UPGRADE)。

         

      7. 运行以下查询,获取无效对象的数量。这个值将在稍后用于作比较,以确保重新编译没有由于纯编译故障而产生额外的无效对象。
        Select count(*)From all_objectsWhere status='INVALID';
      8. 以下查询将为您展示,纯编译模式和解释模式分别编译了多少对象。
        SELECT plsql_code_type, count(*) FROM dba_plsql_object_settings GROUP BY plsql_code_type;

        您可能看到一些对象的 plsql_code_type 为 NULL。这些是特殊的内部对象,可以忽略。

         

      9. cd(更改目录)至 $ORACLE_HOME/rdbms/admin

         

      10. 运行 $ORACLE_HOME/rdbms/admin/dbmsupgnv.sql(作为 SYS 用户)。

        注释 1: dbmsupgnv.sql 使所有的 PL/SQL 模块失效并更新字典表,将它们的 plsql_code_type 设置修改为 NATIVE。这一阶段必须在数据库上没有其他活动进行时完成;因此,我们要求在运行 dbmsupgnv.sql 期间必须以 UPGRADE 模式启动数据库。

        注释 2:如果您要从数据库的一个低版本向数据库高版本升级(例如,升级到 Oracle 数据库 10g),那么您必须首先运行升级脚本,然后运行 dbmsupgnv.sql。例如,如果您正从 9.2.0.3 升级到 10.1.0,那么请首先运行升级脚本 (u0902000.sql),然后关闭数据库并运行 dbmsupgnv.sql 脚本。

         

      11. 在运行 dbmsupgnv.sql 之后提交更改
        SQL> commit;

         

      12. 关闭数据库。

         

      13. 以正常模式重新启动数据库。

         

      14. 运行 $ORACLE_HOME/rdbms/admin/utlrp.sql 脚本(作为 SYS 用户)。这一步骤将重新编译所有的 PL/SQL 模块。[在这个过程期间,您可能想定期查看 plsql_native_library_dir 指定的目录,以确保编译过程的确创建了新的共享库。]

        注意:这一步骤是可重新启动的。如果由于任何原因这个步骤异常终止,那么您只需重新启动这个步骤(即重新运行 utlrp.sql 脚本)。它将重新编译余下的任何无效的 PL/SQL 模块。

         

      15. 在编译成功完成之后,您应当验证无效对象数少于或等于重新编译之前的无效对象数。您可以使用以下查询获取无效对象数。
        Select count(*)From all_objectsWhere status='INVALID';

        再运行以下查询,以确保没有遗漏解释的模块:

        SELECT plsql_code_type, count(*) FROM dba_plsql_object_settings GROUP BY plsql_code_type;
     http://www.oracle.com/technology/global/cn/tech/pl_sql/htdocs/ncomp_faq.html
    原创粉丝点击