native编译通过将PL/SQL单元编译为机器码,提升重复调用时的执行速度和CPU效率,但首次编译更慢、占用更多磁盘空间、调试受限且依赖C编译器;是否启用需结合代码特征(如CPU密集型、高频短逻辑)和部署环境谨慎评估。

直接改 plsql_code_type 不一定能提速,反而可能让首次编译变慢、部署出错;是否启用 native 编译,得看你的代码特征和执行频次。
native 编译到底快在哪,又慢在哪
native 编译把 PL/SQL 单元(过程、函数、包体)编译成机器码,跳过解释器逐行解析字节码的过程,所以重复执行时 CPU 消耗更低、单次调用延迟更小。但它代价也很实在:
- 编译耗时显著增加——尤其含大量逻辑或嵌套调用的包,
CREATE OR REPLACE PACKAGE BODY可能从秒级拖到分钟级 - 生成的 native 代码存放在
SYSTEM表空间,占用更多磁盘空间,且无法跨平台迁移(比如从 Linux 迁到 Windows 就得重编译) - 调试支持弱:DBMS_DEBUG、PL/SQL Profiler 对 native 编译单元的支持有限,堆栈信息可能不完整
- 依赖 Oracle 的 C 编译器链(如
gcc),需确保数据库服务器上已正确配置ORACLE_HOME/lib和编译工具路径
怎么安全地开启 native 编译
别全局改参数,先局部验证。Oracle 不会自动把已有 interpreted 单元转为 native,必须显式重新编译:
- 临时切换当前 session:
ALTER SESSION SET plsql_code_type = native;,再CREATE OR REPLACE你要测的单元 - 批量重编译已有对象,用
dbms_utility.compile_schema并传入compile_all => TRUE和plsql_code_type => 'NATIVE'(注意:这会锁住 schema 中所有 PL/SQL 对象) - 查哪些已编译为 native:
SELECT object_name, plsql_code_type FROM user_plsql_object_settings WHERE plsql_code_type = 'NATIVE'; - 回退方法简单:
ALTER SESSION SET plsql_code_type = interpreted;后重新编译即可,无需清理 SYSTEM 表空间残留
什么情况下 native 真正值得开
不是所有 PL/SQL 都适合 native。重点盯这两类:
- CPU 密集型计算逻辑:比如自定义加密函数、数值积分、递归树遍历、大量字符串拼接与正则替换——这些在 interpreted 下反复调用解释器开销大,native 收益明显
- 高频、短生命周期调用:如 APEX 页面中每秒被调用数百次的校验函数,或 DBMS_SCHEDULER job 中每分钟执行的轻量逻辑,避免每次调用都做字节码解析
-
反例:I/O 主导型过程——比如主体是
INSERT ... SELECT或游标循环更新表的存储过程,native 几乎不改善性能,因为瓶颈在磁盘或锁等待上
容易踩的坑:编译失败、运行报错、监控失灵
native 编译失败通常不报具体错误,只显示 PLS-00923: native compilation failed。常见原因:
- 数据库未启用 C 编译支持:
SELECT * FROM v$option WHERE parameter = 'Native Compilation';必须返回TRUE - 用户缺少
CREATE PROCEDURE+CREATE LIBRARY权限(native 编译内部会创建动态库对象) - 代码里用了
DBMS_OUTPUT.PUT_LINE或UTL_FILE等需运行时链接的包,而对应.so文件未在ORACLE_HOME/lib下注册 - 启用了
plsql_optimize_level = 3后再 native 编译,可能触发某些旧版本优化器 bug,导致运行时报ORA-03113或静默崩溃——建议保持plsql_optimize_level = 2配合 native
最后提醒一句:native 编译不是银弹。19c 起,Oracle 更推荐优先用 BULK COLLECT + FORALL 减少上下文切换、用统计信息+直方图稳住执行计划——这些带来的性能提升,往往比 native 更稳定、更容易验证。











