博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Oracle 数据库的逻辑迁移
阅读量:5891 次
发布时间:2019-06-19

本文共 15134 字,大约阅读时间需要 50 分钟。

  当我们开发完成一个项目/产品,到客户现场进行培训和基础数据的准备时,往往服务器尚在采购之中。这时我们往往会随便找一台配置相对好一点的计算机充当服务器。服务器到货之后,就需要把临时数据库服务器之上的数据迁移到真正的服务器之中。源数据库可能是 Windows 系统、单机、使用文件系统存储数据文件,而目标数据库则可能是 Linux、配置了集群(RAC)、使用ASM存储数据文件。这时就需要进行逻辑数据迁移。

  逻辑数据迁移,一般只需要使用 exp 和 imp 这对导出/导入命令即可。但是,某些大型系统,往往有几十个表空间、几十种角色、上千用户(因为它使用了数据库级别的用户管理),每个用户都拥有不同的对象权限,甚至不同用户之间还会相互做外键引用。这时,单纯使用 exp imp 命令无论如何也不能确保一次将所有数据库对象正确导入。本文将以 Step by Step 的方式提供一系列步骤和脚本完成逻辑数据迁移工作,不敢保证考虑了所有情况,仅供各位童鞋参考。
先给出2个脚本:

导出表空间和用户的创建脚本.sql
declare   is_asm number(1); -- 是否使用ASM管理。如果为1,会忽略表空间文件名,交由Oracle自动管理  target_datafile_path varchar(2000); -- 目标数据库的数据文件路径。例:D:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\ 或 +DATA  v_dbuser_names varchar2(32767); -- 接收用户名列表  source_db_conn varchar2(200); -- 源数据库连接  target_db_conn varchar2(200); -- 目标数据库连接  l_file utl_file.file_type; -- 输出文件begin     --DBMS_OUTPUT.ENABLE(10000000);     execute immediate 'create or replace directory D_OUTPUT as ''D:\TEMP'''; -- 路径必须是数据库服务器上的硬盘!!!    -- 表空间常量设定 Begin  --is_asm := 0;  --target_datafile_path := 'E:\oracle_data\zhis\';    is_asm := 1;  target_datafile_path := '+DATA';  -- 表空间常量设定 End    -- 数据库连接  source_db_conn := '''sys/密码@orcl as sysdba'''; -- 导出时最好用sys用户  target_db_conn := '''sys/密码@zhis as sysdba'''; -- 导入时要用system用户    -- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +  -- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +  -- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +    l_file := utl_file.fopen('D_OUTPUT', '1_creation.sql', 'A');   -- 创建表空间  utl_file.put_line(l_file, '-- 创建表空间');  -- 永久表空间  for c in (select max(tf.tablespace_name) tablespace_name,                   max(ts.contents) ts_contents,                   wm_concat('''' || target_datafile_path || case when is_asm=1 then '' else Substr(tf.file_name, Instr(tf.file_name, '\', -1)+1) end || ''''                             || ' SIZE ' || tf.user_bytes || ' AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED ') datafile_creations              from dba_data_files tf              left join dba_tablespaces ts on tf.tablespace_name = ts.tablespace_name             where ts.tablespace_name not in ('SYSTEM','UNDOTBS1','SYSAUX','TEMP','USERS') -- 排除自带的表空间               and ts.contents ='PERMANENT'             group by ts.tablespace_name)  loop    utl_file.put_line(l_file, 'CREATE TABLESPACE "' || c.tablespace_name || '"');    utl_file.put_line(l_file, '      DATAFILE ' || c.datafile_creations);    utl_file.put_line(l_file, '      LOGGING EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO; ');  end loop;  -- 临时表空间  for c in (select max(tf.tablespace_name) tablespace_name,                   max(ts.contents) ts_contents,                   wm_concat('''' || target_datafile_path || case when is_asm=1 then '' else Substr(tf.file_name, Instr(tf.file_name, '\', -1)+1) end || ''''                             || ' SIZE ' || tf.user_bytes || ' AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED ') datafile_creations              from dba_temp_files tf              left join dba_tablespaces ts on tf.tablespace_name = ts.tablespace_name             where ts.tablespace_name not in ('SYSTEM','UNDOTBS1','SYSAUX','TEMP','USERS') -- 排除自带的表空间               and ts.contents = 'TEMPORARY'             group by ts.tablespace_name)  loop    utl_file.put_line(l_file, 'CREATE TEMPORARY TABLESPACE "' || c.tablespace_name || '"');    utl_file.put_line(l_file, '      TEMPFILE ' || c.datafile_creations);    utl_file.put_line(l_file, '      EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M; ');  end loop;    -- 创建角色  utl_file.put_line(l_file, '-- 创建角色');  for rc in (  select * from dba_roles r  where r.role not in ('CONNECT','RESOURCE','DBA','SELECT_CATALOG_ROLE','EXECUTE_CATALOG_ROLE','DELETE_CATALOG_ROLE',                       'EXP_FULL_DATABASE','IMP_FULL_DATABASE','RECOVERY_CATALOG_OWNER','GATHER_SYSTEM_STATISTICS',                       'LOGSTDBY_ADMINISTRATOR','AQ_ADMINISTRATOR_ROLE','AQ_USER_ROLE','GLOBAL_AQ_USER_ROLE',                       'SCHEDULER_ADMIN','HS_ADMIN_ROLE','AUTHENTICATEDUSER','OEM_ADVISOR','OEM_MONITOR',                       'WM_ADMIN_ROLE','JAVAUSERPRIV','JAVAIDPRIV','JAVASYSPRIV','JAVADEBUGPRIV','EJBCLIENT',                       'JAVA_ADMIN','JAVA_DEPLOY','CTXAPP','XDBADMIN','XDBWEBSERVICES','OLAP_DBA','OLAP_USER','MGMT_USER'))  loop    utl_file.put_line(l_file, 'create role ' || rc.role || ';');    utl_file.put_line(l_file, 'revoke ' || rc.role || ' from SYS;'); -- 因为创建了角色的用户会自动拥有该角色的权限,而Oracle默认又有启用角色不允许超过148个的限制,所以这里在创建了之后要把角色从当前用户里面移除。        -- 授权    for rrpc in (    select * from role_role_privs rrp     where rrp.role = rc.role)    loop      utl_file.put_line(l_file, 'grant ' || rrpc.granted_role || ' to ' || rc.role                            || case when rrpc.admin_option = 'YES' then ' with admin option' else '' end || ';');    end loop;     for rspc in (    select * from role_sys_privs rsp     where rsp.role = rc.role)    loop      utl_file.put_line(l_file, 'grant ' || rspc.privilege || ' to ' || rc.role                            || case when rspc.admin_option = 'YES' then ' with admin option' else '' end || ';');    end loop;  end loop;  -- 创建用户  utl_file.put_line(l_file, '-- 创建用户');  for c in (  select u.* from dba_users u   where u.username not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                            'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB'))  loop    utl_file.put_line(l_file, 'create user ' || c.username);    utl_file.put_line(l_file, '    identified by values ''' || c.password || '''');    utl_file.put_line(l_file, '    default tablespace ' || c.default_tablespace);    utl_file.put_line(l_file, '    temporary tablespace ' || c.temporary_tablespace || ';');        -- 授权    for spc in (    select sp.* from dba_sys_privs sp     where sp.grantee = c.username)    loop      utl_file.put_line(l_file, 'grant ' || spc.privilege || ' to ' || c.username || ';');    end loop;        for rpc in (    select rp.* from dba_role_privs rp     where rp.grantee = c.username)    loop      utl_file.put_line(l_file, 'grant ' || rpc.granted_role || ' to ' || c.username || ';');    end loop;  end loop;    utl_file.fflush(l_file);   utl_file.fclose(l_file);     l_file := utl_file.fopen('D_OUTPUT', '3_grand_obj_privs.sql', 'A');   -- 角色的对象授权  utl_file.put_line(l_file, '-- 角色的对象授权');  for rc in (  select * from dba_roles r  where r.role not in ('CONNECT','RESOURCE','DBA','SELECT_CATALOG_ROLE','EXECUTE_CATALOG_ROLE','DELETE_CATALOG_ROLE',                       'EXP_FULL_DATABASE','IMP_FULL_DATABASE','RECOVERY_CATALOG_OWNER','GATHER_SYSTEM_STATISTICS',                       'LOGSTDBY_ADMINISTRATOR','AQ_ADMINISTRATOR_ROLE','AQ_USER_ROLE','GLOBAL_AQ_USER_ROLE',                       'SCHEDULER_ADMIN','HS_ADMIN_ROLE','AUTHENTICATEDUSER','OEM_ADVISOR','OEM_MONITOR',                       'WM_ADMIN_ROLE','JAVAUSERPRIV','JAVAIDPRIV','JAVASYSPRIV','JAVADEBUGPRIV','EJBCLIENT',                       'JAVA_ADMIN','JAVA_DEPLOY','CTXAPP','XDBADMIN','XDBWEBSERVICES','OLAP_DBA','OLAP_USER','MGMT_USER'))  loop    for rtpc in (    select * from role_tab_privs rtp     where rtp.role = rc.role)    loop      utl_file.put_line(l_file, 'grant ' || rtpc.privilege || ' on ' || rtpc.owner || '.' || rtpc.table_name || ' to ' || rc.role || ';');    end loop;  end loop;    -- 用户的对象授权  utl_file.put_line(l_file, '-- 用户的对象授权');  for c in (  select u.* from dba_users u   where u.username not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                            'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB'))  loop     for tpc in (    select tp.* from dba_tab_privs tp     where tp.grantee = c.username)    loop      utl_file.put_line(l_file, 'grant ' || tpc.privilege || ' on ' || case when tpc.privilege in ('READ','WRITE') then ' directory ' else '' end                           || tpc.owner || '.' || tpc.table_name || ' to ' || c.username                            || case when tpc.grantable = 'YES' then ' with grant option ' else '' end || ';');    end loop;  end loop;    utl_file.fflush(l_file);   utl_file.fclose(l_file);     l_file := utl_file.fopen('D_OUTPUT', '2_exp_imp.txt', 'A');     -- 导出和导入命令   select wm_concat('''' || u.username || '''') into v_dbuser_names    from dba_users u   where u.username not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                            'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB')     and u.username in (select distinct o.owner from dba_objects o); -- 拥有对象的用户  utl_file.put_line(l_file, 'exp ' || source_db_conn || ' owner=(' || v_dbuser_names || ') file="D:\sourcedb.dmp" log="D:\sourcedbexp.log" GRANTS=N COMPRESS=N');  /*for uc in (  select u.username    from dba_users u   where u.username not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                            'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB')     and u.username in (select distinct o.owner from dba_objects o))  loop    utl_file.put_line(l_file, 'imp ' || target_db_conn || ' file="D:\sourcedb.dmp" log="D:\imp_' || uc.username || '.log" GRANTS=N'                      || ' fromuser=' || uc.username || ' touser=' || uc.username);  end loop;*/  utl_file.put_line(l_file, 'imp ' || target_db_conn || ' full=Y file="D:\sourcedb.dmp" log="D:\sourcedbimp.log" GRANTS=N');    utl_file.fflush(l_file);   utl_file.fclose(l_file); end;
创建缺失的对象.sql
declare   l_file utl_file.file_type; -- 输出文件begin  execute immediate 'create or replace directory D_OUTPUT as ''D:\TEMP'''; -- 路径必须是数据库服务器上的硬盘!!!  l_file := utl_file.fopen(location => 'D_OUTPUT',                    filename => '4_create_objs19.sql',                    open_mode => 'A',                    max_linesize => 32767);   -- 创建外键  utl_file.put_line(l_file, '-- 创建缺失的外键');  for c in   (  SELECT DBMS_METADATA.get_ddl('REF_CONSTRAINT', sc.constraint_name, sc.owner) ddl_text    FROM dba_constraints sc   where sc.constraint_type='R'     and sc.owner || sc.constraint_name not in (select tc.owner || tc.constraint_name                                                  from dba_constraints@targetdb tc                                                 where tc.owner not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                                                                        'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB'))     and sc.owner not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                          'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB'))  loop    utl_file.put_line(l_file, c.ddl_text || ';');    utl_file.fflush(l_file);   end loop;      -- 创建缺失的视图  utl_file.put_line(l_file, '-- 创建缺失的视图');  for c in   (select DBMS_METADATA.get_ddl('VIEW', v.view_name, v.owner) ddl_text     from dba_views v    where v.owner || v.view_name not in (select tv.owner || tv.view_name from dba_views@targetdb tv                                          where tv.owner not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                                                                 'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB'))      and v.owner not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                          'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB'))                                                                   loop    utl_file.put_line(l_file, c.ddl_text || ';');    utl_file.fflush(l_file);   end loop;    -- 创建缺失的函数和存储过程  utl_file.put_line(l_file, '-- 创建缺失的函数和存储过程');  for c in   (select DBMS_METADATA.get_ddl(o.object_type,  o.object_name, o.owner) ddl_text     from dba_objects o    where o.object_type in ('PACKAGE','FUNCTION','PROCEDURE')     and o.owner || o.object_name not in (select t.owner || t.object_name from dba_objects@targetdb t                                           where t.owner not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                                                                 'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB'))     and o.owner not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                            'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB'))  loop    utl_file.put_line(l_file, c.ddl_text);    utl_file.fflush(l_file);   end loop;    -- 创建缺失的同义词  utl_file.put_line(l_file, '-- 创建缺失的同义词');  for c in (  select s.*, DBMS_METADATA.get_ddl('SYNONYM',  s.synonym_name, s.owner) ddl_text     from dba_synonyms s   where s.owner || s.synonym_name not in (select ts.owner || ts.synonym_name from dba_synonyms@targetdb ts                                            where ts.owner not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                                                                   'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB'))     and s.owner not in ('ANONYMOUS','CTXSYS','DBSNMP','DIP','DMSYS','EXFSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORDPLUGINS',                         'ORDSYS','OUTLN','SCOTT','SI_INFORMTN_SCHEMA','SYS','SYSMAN','SYSTEM','TSMSYS','WMSYS','XDB'))  loop     utl_file.put_line(l_file, c.ddl_text || ';');     utl_file.fflush(l_file);   end loop;    utl_file.fflush(l_file);   utl_file.fclose(l_file);               end;

Step1:以 sys 用户登录源数据库,执行“导出表空间和用户的创建脚本.sql”。

  在执行之前,要确认脚本中的几个参数:

  D_OUTPUT 参数是服务器硬盘上路径,默认为d:\temp,确保文件夹已创建。
  source_db_conn 和 target_db_conn 为源数据库和目标数据库的用户名、密码和服务命名,要使用 sys 用户。
  is_asm 表示目标数据库是否使用ASM管理数据文件。
  target_datafile_path 是目标数据库数据文件的路径。

  执行此脚本会在数据库所在服务器硬盘 d:\temp 创建3个文件:

  1_creation.sql 创建表空间和用户的数据库脚本。
  2_exp_imp.txt 导出和导入命令。
  3_grand_obj_privs.sql 给对象赋予权限的数据库脚本。

Step2:以 sys 用户登录目标数据库,执行 “1_creation.sql”,创建表空间和用户。

Step3:打开命令行,执行exp_imp.txt里的导出命令。

Step4:打开命令行,执行exp_imp.txt里的导入命令。注:在Windows下,如果想要以sys用户导入导出,需要加引号,例如 imp as sysdba' ...;而在 linux 系统下,则要写成  imp \ as sysdba\' ...

Step5:打开 Step4 生成的 d:\sourcedbimp.log,搜索IMP开头的信息,确认有哪些对象导入失败。

Step6:以sys登录源数据库,创建指向目标数据库的数据链接,然后执行“创建缺失的对象.sql”。此脚本将生成“4_create_objs.sql”。

Step7:以sys登录目标数据库,执行4_create_objs.sql,可以将 Step5 导入失败的外键、视图、存储过程和同义词等再创建一遍。

Step8:使用PL/SQL Developer,以sys登录目标数据库,使用菜单 Tools|Compile Invalid Objects...,编译所有无效对象。

转载于:https://www.cnblogs.com/1-2-3/archive/2012/09/27/oracle-logic-data-migration.html

你可能感兴趣的文章
十大开源ERP点评 献给深水区的中小企业和CIO们
查看>>
Oracle --存储函数和存储过程
查看>>
Windows Server 2008 R2 SP1 关闭IE ESC (Internet Explorer 增强的安全配置)
查看>>
DT系统开发之-文件结构目录
查看>>
Android Looper简介
查看>>
【PHP】创蓝253云通信平台国际短信接口调用demo案例
查看>>
Confluence 6 重要缓存和监控
查看>>
Day 30 shell 编程
查看>>
静态路由和默认路由
查看>>
谈一谈Spring-Mybatis在多数据源配置上的坑
查看>>
2.1 shell语句
查看>>
【精益生产】车间现场管理的八大浪费
查看>>
springMVC国际化
查看>>
变频电源内部的元器件是有着什么样的发挥和作用
查看>>
hadoop+spark+scala环境--单实例版
查看>>
数组排序_冒泡排序、选择排序、快速排序
查看>>
mybatis写xml时注意事项
查看>>
关于阿里开发者招聘节 |这5道笔试真题 你会吗!???
查看>>
C#的异常处理机制
查看>>
Redis学习手册(内存优化)
查看>>