将完整的Oracle 11g数据库模式从脚本

时间:2015-11-14 03:02:36

标签: oracle11g metadata ddl

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

使用我最喜欢的RDBMS,,使用pg_dump --schema-only,这是一项几乎简单易用的任务

但是,使用Oracle 11g将Oracle DB模式转储到SQL文件已经证明是一项非常困难的任务。我很想知道其他人已经想到的方法。

数据泵导出(否☹)

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

SQL开发人员

我已经使用了Oracle的SQL开发人员GUI,而 主要使用"分离文件"设定:

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

然而,它有几个主要问题:

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

SQL developer export settings

expimp

Oracle年龄较大的exp command-line tool 需要DBA访问权限。它可以导出数据库的完整DDL(具有DBA访问权限),或仅导出单个用户拥有的对象的DDL。

不幸的是,它甚至比SQL开发人员更慢(即使使用a few performance tweaks,同一数据库也需要1小时。

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

相应的imp tool可以"翻译"这些转储文件被严重损坏的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"

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

DBMS_METADATA

Oracle有一个dbms_metadata包,它支持内省数据库内容。

编写一个SQL语句相对容易,该语句将检索某些但不是所有数据库对象的DDL。例如,以下语句将检索CREATE TABLE语句,但不会在这些表上检索相应的权限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

尝试快速获取整套物体会导致一个非常复杂的兔子洞。 (有关更多详细信息,请参阅"Reverse engineering object DDL and finding object dependencies"。)

还有什么?

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

1 个答案:

答案 0 :(得分:1)

结合DBMS_DATAPUMP,Oracle Copy (OCP)和一个简单的shell脚本来创建一键式解决方案。

要导出的示例架构

--Create test user.
drop user test_user cascade;
create user test_user identified by test_user;
create table test_user.table1(a number);
create view test_user.view1 as select 1 a from dual;
create or replace procedure test_user.procedure1 is begin null; end;
/

创建目录和程序

以SYS作为步骤运行它们。定义者权限过程以SYS身份运行。这样就不需要为任何用户授予任何角色或特权。

--Create directory that will contain SQL file.
create directory ddl_directory as 'C:\temp';
grant read on directory ddl_directory to jheller;

--Create procedure that can only export one hard-coded schema.
--This is based on René Nyffenegger's solution here:
--dba.stackexchange.com/questions/91149/how-to-generate-an-sql-file-with-dbms-datapump
create or replace procedure sys.generate_ddl authid definer is

    procedure create_export_file is
      datapump_job number;
      job_state    varchar2(20);
    begin
        datapump_job := dbms_datapump.open(
            operation    => 'EXPORT',
            job_mode     => 'SCHEMA',
            remote_link  =>  null,
            job_name     => 'Export dump file',
            version      => 'LATEST');

        dbms_output.put_line('datapump_job: ' || datapump_job);

        dbms_datapump.add_file(
            handle    =>  datapump_job,
            filename  => 'export.dmp',
            directory => 'DDL_DIRECTORY',
            filetype  =>  dbms_datapump.ku$_file_type_dump_file);

        dbms_datapump.metadata_filter(
            handle    =>  datapump_job,
            name      =>  'SCHEMA_LIST',
            value     =>  '''TEST_USER''');

        dbms_datapump.start_job(
            handle       => datapump_job,
            skip_current => 0,
            abort_step   => 0);

        dbms_datapump.wait_for_job(datapump_job, job_state);

        dbms_output.put_line('Job state: ' || job_state);

        dbms_datapump.detach(datapump_job);
    end create_export_file;


    procedure create_sql_file is
        datapump_job number;
        job_state    varchar2(20);
    begin
        datapump_job := dbms_datapump.open(
            operation    => 'SQL_FILE',
            job_mode     => 'SCHEMA',
            remote_link  =>  null,
            job_name     => 'Export SQL file',
            version      => 'LATEST');

        dbms_output.put_line('datapump_job: ' || datapump_job);

        dbms_datapump.add_file(
            handle    =>  datapump_job,
            filename  => 'export.dmp',
            directory => 'DDL_DIRECTORY',
            filetype  =>  dbms_datapump.ku$_file_type_dump_file);

        dbms_datapump.add_file(
            handle    =>  datapump_job,
            filename  => 'schema.sql',
            directory => 'DDL_DIRECTORY',
            filetype  =>  dbms_datapump.ku$_file_type_sql_file);

        dbms_datapump.start_job(
            handle       => datapump_job,
            skip_current => 0,
            abort_step   => 0);

        dbms_datapump.wait_for_job(datapump_job, job_state);

        dbms_output.put_line('Job state: ' || job_state);

        dbms_datapump.detach(datapump_job);
    end create_sql_file;

begin
    create_export_file;
    create_sql_file;
end;
/

--Grant to users.
grant execute on generate_ddl to jheller;

在客户端设置OCP

this answer中所述,可以使用OCP轻松地将Oracle目录中的文件传输到客户端PC。设置  有点棘手 - 下载程序的精确版本和即时客户端并将它们解压缩到同一目录中。我想我也遇到了一些问题  一个VC ++可再发行组件或第一次的东西。

要运行的命令

现在简单的部分 - 创建和移动文件只需两个简单的步骤:

execute sys.generate_ddl;

C:\Users\jonearles\Downloads\ocp-0.1-win32>ocp jheller/jheller@orcl12 DDL_DIRECTORY:schema.sql schema.sql

示例输出

这个脚本包含很多奇怪的东西。一些没有人会理解的奇怪的额外命令,以及一些没有人会理解的奇怪选项。这可能是这个看似显而易见的特征如此困难的原因之一 - 由于成千上万的奇怪特征,输出既不可理解也不完全明确。

CREATE TABLE "TEST_USER"."TABLE1" 
   (    "A" NUMBER
   ) SEGMENT CREATION DEFERRED 
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 
 NOCOMPRESS LOGGING
  TABLESPACE "USERS" ;

...

-- new object type path: SCHEMA_EXPORT/PROCEDURE/PROCEDURE
-- CONNECT TEST_USER
CREATE EDITIONABLE procedure           procedure1 is begin null; end;
/

...

-- new object type path: SCHEMA_EXPORT/VIEW/VIEW
CREATE FORCE EDITIONABLE VIEW "TEST_USER"."VIEW1" ("A") AS 
  select 1 a from dual
;