将完整的 Oracle 11g 数据库模式从脚本转储到一组 SQL 创建语句

Dan*_*ski 5 ddl metadata oracle11g

我需要将Oracle 数据库的完整模式(仅,无数据)转储到文本文件或一组文本文件,以便能够使用标准 VCS 工具(如系统地跟踪对数据库模式的修订。

使用我最喜欢的 RDBMS ,这是一项几乎微不足道的简单任务,使用pg_dump --schema-only.

然而,事实证明,使用 Oracle 11g 将 Oracle DB 模式转储到 SQL 文件是一项非常困难的任务。我有兴趣了解其他人已经找到的方法。

数据泵导出(否?)

不幸的是,我无法使用数据泵导出Oracle 10g 中引入工具,因为这些工具需要 DBA 级别的访问权限,而对于我的大多数客户的数据库,我无法轻松获得此级别的访问权限。

SQL 开发人员

我使用过 Oracle 的 SQL 开发人员 GUI,它主要通过“单独文件”设置完成我想要的操作:

  • 发出一个语法正确的 SQL 文件来创建每个数据库对象
  • 发出一个摘要 SQLs 文件,该文件以正确的顺序包含每个单独的对象文件

但是,它有几个主要问题:

  • 它只是一个 GUI;据我所知,无法从命令行编写此行为的脚本
  • 作为非特权用户运行,它只能为该用户拥有的对象发出 DDL(即使该用户已被授予查看其他用户对象的权限...... @#$​​(*&!! )
  • 非常慢,大约需要 20 分钟才能输出大约 1 MB 的 DDL

SQL 开发人员导出设置

expimp

Oracle的旧的exp命令行工具确实要求具有DBA权限。它可以导出数据库的完整 DDL(具有 DBA 访问权限),或仅导出单个用户拥有的对象的 DDL。

不幸的是,它甚至比 SQL 开发人员还要慢(即使有一些性能调整,对于同一个数据库也需要 1 小时以上

然而,关于最糟糕的事情exp是,它并没有发出SQL,而是一个专有的二进制格式的转储文件(例如,expdat.dmp)。

相应的imp工具可以将这些转储文件“翻译”为严重损坏的 SQL,其中不包含语法正确的语句结束分隔符

imp show=y发出的可怕的错误 SQL 的示例;请注意一些但不是所有语句的末尾疯狂的换行和缺少分号。

Export file created by EXPORT:V11.02.00 via direct path
import done in US7ASCII character set and AL16UTF16 NCHAR character set
import server uses AL32UTF8 character set (possible charset conversion)
. importing FPSADMIN's objects into FPSADMIN
 "BEGIN  "
 "sys.dbms_logrep_imp.instantiate_schema(schema_name=>SYS_CONTEXT('USERENV','"
 "CURRENT_SCHEMA'), export_db_name=>'*******', inst_scn=>'371301226');"
 "COMMIT; END;"
 "CREATE TYPE "CLOBSTRINGAGGTYPE" TIMESTAMP '2015-06-01:13:37:41' OID '367CDD"
 "7E59D14CF496B27D1B19ABF051'           "
 "AS OBJECT"
 "("
 "     theString CLOB,"
 "     STATIC FUNCTION"
 "          ODCIAggregateInitialize(sctx IN OUT CLOBSTRINGAGGTYPE )"
 "          RETURN NUMBER,"
 "     MEMBER FUNCTION"
 "          ODCIAggregateIterate(self IN OUT CLOBSTRINGAGGTYPE, VALUE IN VARC"
 "HAR2 )"
 "          RETURN NUMBER,"
 "     MEMBER FUNCTION"
 "          ODCIAggregateTerminate(self IN CLOBSTRINGAGGTYPE, returnValue OUT"
 " CLOB, flags IN NUMBER)"
 "          RETURN NUMBER,"
 "     MEMBER FUNCTION"
 "          ODCIAggregateMerge(self IN OUT CLOBSTRINGAGGTYPE, ctx2 IN CLOBSTR"
 "INGAGGTYPE)"
 "          RETURN NUMBER"
 ");"
 "GRANT EXECUTE ON "CLOBSTRINGAGGTYPE" TO PUBLIC"
 "GRANT DEBUG ON "CLOBSTRINGAGGTYPE" TO PUBLIC"
 "CREATE OR REPLACE TYPE BODY          CLOBSTRINGAGGTYPE"
Run Code Online (Sandbox Code Playgroud)

我编写了一个 Python 脚本来对 的输出进行解码imp show=y,但它无法可靠地对输出进行解码,因为它不了解完整的 Oracle SQL 语法。

dbms_metadata

甲骨文有一个 dbms_metadata支持数据库内容自省的包。

编写一个 SQL 语句来检索某些但不是所有数据库对象的 DDL 相对容易。例如,以下语句将检索CREATE TABLEstatements,但不会检索GRANT这些表上的相应权限。

select sub.*, dbms_metadata.get_ddl(sub.object_type, sub.object_name, sub.owner) sql
from (
    select
        created,
        owner,
        object_name,
        decode(object_type,
            'PACKAGE',      'PACKAGE_SPEC',
            'PACKAGE BODY', 'PACKAGE_BODY',
            'TYPE BODY', 'TYPE_BODY',
            object_type
        ) object_type
    from all_objects 
    where owner = :un
        --These objects are included with other object types.
        and object_type not in ('INDEX PARTITION','LOB','LOB PARTITION','TABLE PARTITION','DATABASE LINK')
        --Ignore system-generated types that support collection processing.
        and not (object_type like 'TYPE' and object_name like 'SYS_PLSQL_%')
) sub
Run Code Online (Sandbox Code Playgroud)

试图快速获取完整的对象集会导致一个非常复杂的兔子洞。(有关更多详细信息,请参阅“逆向工程对象 DDL 和查找对象依赖项”。)

还有什么?

有什么建议吗?我完全失去了一种理智且可维护的方式来执行这个看似不可或缺的数据库编程任务。