3000字详解:Oracle 19c 数据泵恢复实战经验分享

本文会从环境准备开始,包括创建可插拔数据库(PDB)、表空间的创建与管理、用户账号的配置、字符集的调整,一直到数据导入的具体步骤,另外还会分享一些导入时常见问题解决。希望通过这些经验和技巧,能让在处理类似任务时有到启发。

一、环境准备

(一)创建pdb

首先准备环境,创建pdb,用于恢复

--  使用克隆模式 创建 PDB
CREATE PLUGGABLE DATABASE [PdbName] ADMIN USER [AdminUser] IDENTIFIED BY [AdminPaswd]
FILE_NAME_CONVERT=('[/data/oracle/ORADB/pdbseed/]', '[/data/oracle/[PdbName]/]'
);
--[更换为自己的实际相关参数],比如所对应的[PDB1],[admin],[dhjhjd3dh11]
CREATE PLUGGABLE DATABASE PDB1 ADMIN USER admin IDENTIFIED BY dhjhjd3dh11
FILE_NAME_CONVERT=('/data/oracle/ORADB/pdbseed/', '/data/oracle/PDB1/'
);
--查询可被克隆的PDB以及地址,也就是FILE_NAME_CONVERT的第一个参数
SELECT FILE#, NAME, CON_ID
FROM V$DATAFILE;
--或者
SELECT FILE#, NAME, CON_ID
FROM V$DATAFILE
WHERE CON_ID = 2;
    CON_ID
----------
	 5
/data/oracle/ORADB/pdbseed/system01.dbf
	 2

	 6
/data/oracle/ORADB/pdbseed/sysaux01.dbf
	 2

	 8
/data/oracle/ORADB/pdbseed/undotbs01.dbf
	 2

(二)表空间创建

1.查询需要创建的表空间

❗在这里需要查询一下源库中需要单独创建哪些表空间,避免导入时报错,另外需要规划好表空间大小。使用以下方式进行查询

-- 在源库上查询需要单独创建的表空间,“[OwnerName]替换成实际的owner”
select distinct tablespace_name  from dba_segments    where owner = '[OwnerName]';
-- 源库查询表空间需要创建多大,查看已用表空间来进行分配表空间大小。“[OwnerName]替换成实际的owner”。
SELECT tablespace_name, 
       SUM(bytes) / 1024 / 1024 / 1024 AS "总大小(GB)", 
       SUM(bytes) / 1024 / 1024 / 1024 - SUM(free_space) / 1024 / 1024 / 1024 AS "已用大小(GB)",
       SUM(free_space) / 1024 / 1024 / 1024 AS "剩余大小(GB)"
FROM (
    SELECT tablespace_name, bytes, 0 AS free_space
    FROM dba_data_files
    UNION ALL
    SELECT tablespace_name, 0 AS bytes, bytes AS free_space
    FROM dba_free_space
)
WHERE tablespace_name IN (
    SELECT DISTINCT tablespace_name
    FROM dba_segments
    WHERE owner = '[OwnerName]'
)
GROUP BY tablespace_name;

2.创建表空间

❗需要切换到刚刚创建的pdb中执行。创建表空间有两种方式,分别为普通表空间,大文件表空间。

(1) 创建普通表空间

表空间初始大小为 30GB,文件会自动扩展,每次扩展 1GB。MAXSIZE 最大为100G

CREATE TABLESPACE [TABLESPACEName]
DATAFILE '[/path/to/datafile1.dbf]' SIZE 30G AUTOEXTEND ON NEXT 1G MAXSIZE 100G;
由于受最大块数(DB_BLOCK_SIZE)限制,无法创建较大文件,普通表空间到达一定大小左右就需要重新添加数据文件。
ALTER TABLESPACE [TABLESPACEName] ADD DATAFILE '[/path/to/datafile2.dbf]' SIZE 20G AUTOEXTEND ON NEXT 1G MAXSIZE 50G;
(2)创建大文件表空间

创建一个大文件表空间(Bigfile Tablespace),表空间中只有一个数据文件文件初始大小为 100GB,每次扩展 1GB,无限制 (MAXSIZE UNLIMITED),适合支持大规模数据的系统,简化了数据文件的管理(仅需管理一个文件)。缺点是单一文件过大会集中 I/O 压力,可能影响性能。如果文件受损或需要迁移,可能会影响整个表空间,这种概率很低但是也得考虑

CREATE BIGFILE [TABLESPACE] example_bigfile
DATAFILE '[/path/to/datafile.dbf]' SIZE 100G AUTOEXTEND ON NEXT 1024M MAXSIZE UNLIMITED;

(3)比较和选择

属性 普通表空间 大文件表空间
数据文件数量 多个(最多 1022 个) 一个
单文件大小 通常受 DB_BLOCK_SIZE 限制(如 32GB) 最大可达 32TB 或更高(取决于配置)
管理复杂性 高(需要管理多个数据文件) 低(仅管理一个文件)
元数据开销 高(多个文件增加元数据)
I/O 性能 支持分布式 I/O,性能更高 I/O 集中,可能导致性能瓶颈
适用场景 中小型应用,数据增长相对稳定 超大规模系统,如数据仓库或云数据库

(三)创建账号

❗基于SCHEMAS模式数据泵只导出指定用户(模式)的对象,不会导出用户本身或角色信息。需手动创建用户。如果导入指定 SCHEMAS= SCHEMASNAME,则不用创建 SCHEMAS,需要创建当前PDB下的其他自建账号。

-- 查询需要创建哪些账号,如果还有其他需要排除的在这里补充'[OTHERNAME]'
SELECT username, created
FROM DBA_USERS
WHERE username NOT IN (
    'SYS', 'SYSTEM', 'DBSNMP', 'SYSMAN', 'MDSYS', 'OLAPSYS', 'ORDSYS', 
    'CTXSYS', 'XDB', 'OUTLN', 'WKSYS', 'DIP', 'EXFSYS', 'LBACSYS', 
    'APPQOSSYS', 'REMOTE_SCHEDULER_AGENT', 'OJVMSYS', 'GSMADMIN_INTERNAL',
    'SYSBACKUP', 'SYSDG', 'SYSKM', 'AUDSYS', 'ANONYMOUS', 'SCOTT',
    'XS$NULL', 'GGSYS', 'DVSYS', 'DVF', 'PDBADMIN', 'APPUSER','[OTHERNAME]'
)
AND username NOT LIKE 'APEX%'  -- 过滤 APEX 用户
AND username NOT LIKE 'FLOWS_%'  -- 过滤 APEX 的旧版本用户
AND username NOT LIKE 'ORA%'  -- 过滤 Oracle 预留的 ORA 开头用户
AND username NOT LIKE 'XS$%'  -- 过滤系统特殊用户
AND ACCOUNT_STATUS = 'OPEN'  -- 只查询启用的用户
ORDER BY created;
-- 创建账号
CREATE USER [USERNAME] IDENTIFIED BY [Password];
GRANT CREATE SESSION TO [USERNAME];
GRANT [权限] TO [USERNAME];

(四)创建导入目录以及授权导入账号权限

--切入到需要导入的pdb下
alter session set container=[PDBName];
--创建导入的目录
create directory dump_dir as '/data/input';
--授权导入账号的权限,我这里直接使用的system,也可根据需求改成相应其他账号
grant read,write on directory dump_dir to [system];

(五)更改字符集

创建库设置了默认字符集,如果需要更改字符集,根据以下操作,下面介绍将UTF8更改为GBK。

❗需要注意的是不能使用下面方式将GBK转为UTF-8

--切换PDB
alter session set container=[PDBName];

--启动pdb
startup;


--启用Oracle数据库的受限模式。在受限模式下,只有特定的用户(通常是管理员)可以连接到数据库,而其他用户则无法连接。
-- 这通常用于进行维护或紧急情况下的数据库访问控制。
ALTER SYSTEM ENABLE RESTRICTED SESSION;

-- 更改字符集

ALTER DATABASE CHARACTER SET INTERNAL_USE ZHS16GBK;



--查看字符集
select userenv('language') from dual;

USERENV('LANGUAGE')
--------------------------------------------------------------------------------
AMERICAN_AMERICA.ZHS16GBK

--关闭受限模式
ALTER SYSTEM DISABLE RESTRICTED SESSION;

二、导入步骤

(一)把需要恢复的文件传到 dump_dir并解压

❗需要注意dump_dir目录权限

--切换到dump_dir
cd /data/input
--解压
tar -zxvf dmpname_xxx.tar.gz 
dmpname_xxx.dmp
dmpname_xxx.dmp.log
--解压后有两个文件,一个说是数据泵文件,一个是导出时候的日志,导出后的日志可以看到导出的一些详细信息,如果后续需要对对象进行验证,可以参考日志中的内容,比如表的数据量,表大小之类

(二)执行导入

--执行导入
nohup impdp system/[password]@10.153.x.x:1521/[PDBName] DUMPFILE=dmpname_xxx.dmp
DIRECTORY=dump_dir  logfile=xx_EXP.log SCHEMAS=[SCHEMASName]  PARALLEL=8 >xx_nohup_"$(date +'%Y-%m-%d_%H-%M-%S').log"&

--1. nohup允许命令在后台运行,即使用户注销终端后,任务也不会中断。
--2. impdp 数据泵导入工具,用于导入从 `expdp` 导出的数据文件。
--3. system/[password]@10.153.x.x:1521/[PDBName]
	--`system`: Oracle 的用户(在这里是 `SYSTEM` 用户)。
	--`[password]`: `SYSTEM` 用户的密码。
	--`10.153.x.x`: Oracle 数据库所在服务器的 IP 地址。
	--`1521`: Oracle 数据库监听的端口号。
	--`[PDBName]`: Oracle 数据库中的容器数据库(Pluggable Database)的名称。
--4. DUMPFILE=dmpname_xxx.dmp指定要导入的数据泵文件名称。
--5. DIRECTORY=dump_dir 指定数据泵文件所在的目录。这个目录名是一个 Oracle 数据库中创建的逻辑目录对象,对应服务器上的物理路径。
--6. logfile=xx_EXP.log指定导入操作的日志文件名称,日志记录导入过程中的信息、警告和错误。
--7. SCHEMAS=[SCHEMASName]指定要导入的数据库模式(Schema)。如果这里和导入的schema不一致需要修改为remap_schema=[源schema账号]:[导入环境的schema账号]
--8. PARALLEL=8指定并行导入的工作进程数量(这里是 8 个)。
--9. >xx_nohup_"$(date +'%Y--%m--%d_%H--%M--%S').log" 将命令的标准输出重定向到文件xx_nohup_"$(date +'%Y--%m--%d_%H--%M--%S').log"
--10. & 将整个导入任务放到后台运行,使用户可以继续使用终端。

三、其他常见的问题

(一)卡在视图导入,进程夯住的解决方法。

❗oracle19c 存在bug Import Hangs During Import of Views in 19c (Doc ID 2676946.1),具有较高递归的复杂视图导入时会导致作业任务夯住

1.解决方法1

PSU/RU补丁打到最新,目前博主打的36582781是已经修复了这个问题

2.解决方法2

手动跳过卡主视图再次导入

-- 1、查看作业任务
sqlplus system/[password]@10.153.x.x:1521/[PDBName]
col owner_name for a20
col job_name for a20
col state for a20
set linesize 1000
col operation for a20
col job_mode for a20
select * from dba_datapump_jobs;
-- 2、根据活跃的作业任务查看impdp,看卡在哪个视图
impdp attach=SYS_IMPORT_SCHEMA_01
system/[password]@10.153.x.x:1521/[PDBName]

--3、跳过视图
nohup impdp system/[password]@10.153.x.x:1521/[PDBName]  DUMPFILE=dmpname_xxx.dmp DIRECTORY=dump_dir logfile=xx_view_dump_dir_EXP$(date +'%Y-%m-%d_%H-%M-%S').log SCHEMAS=[SCHEMASName]  PARALLEL=8 exclude=sequence,table,index,comment,function,procedure,constraint,VIEW:\"IN \(\'[view1]\',\'[view2]\',\'[view3]\'\)\"> XX_VIEW_nohup_$(date +'%Y-%m-%d_%H-%M-%S').log 2>&1 &

--4、如果卡的视图较多,这个需要多次重复操作
--卡在某个任务,可以先
impdp attach=SYS_IMPORT_SCHEMA_02
system/[password]@10.153.x.x:1521/[PDBName]
stop_job=immediate
--然后再加上需要通过的视图再导。比较麻烦

(二)单独导入差别对象

--查看验证是否对应最新序列
SELECT sequence_owner, sequence_name, last_number, max_value, increment_by, cache_size
FROM all_sequences
WHERE sequence_owner = '[sequence_owner_NAME]';
--或  
select count(*) FROM all_sequences WHERE sequence_owner = '[sequence_owner_NAME]';

--如果导入Oracle  ORA-31684 错误,这表明序列未能被覆盖或替换。

--要解决这个问题手动删除序列,通过执行 DROP SEQUENCE 语句来删除现有的序列,然后再重新导入。例如:
DROP SEQUENCE [sequence_owner_NAME].[sequenceName];
--如果序列上有依赖约束,可以使用 CASCADE CONSTRAINTS 选项来删除序列及其所有依赖关系:
DROP SEQUENCE  [sequence_owner_NAME].[sequenceName]CASCADE CONSTRAINTS;

--或者也可以直接全部给删除了重新导入
SET SERVEROUTPUT ON
DECLARE
  CURSOR c_sequences IS
    SELECT sequence_name
    FROM all_sequences
    WHERE sequence_owner = '[sequenceName]';  -- 修改为你的目标模式
  v_sequence_name all_sequences.sequence_name%TYPE;
BEGIN
  FOR rec IN c_sequences LOOP
    v_sequence_name := rec.sequence_name;
    EXECUTE IMMEDIATE 'DROP SEQUENCE ' || v_sequence_name;
    dbms_output.put_line('Sequence ' || v_sequence_name || ' dropped.');
  END LOOP;
END;
/
--导入
nohup impdp system/[password]@10.153.x.x:1521/[PDBName]  DUMPFILE=dmpname_xxx.dmp DIRECTORY=dump_dir logfile=xx_sequence_dump_dir_EXP$(date +'%Y-%m-%d_%H-%M-%S').log SCHEMAS=[SCHEMASName]  PARALLEL=8  INCLUDE=SEQUENCE   TABLE_EXISTS_ACTION=REPLACE   >XX_sequence_nohup_$(date +'%Y-%m-%d_%H-%M-%S').log 2>&1 &

(三)查询导入的对象数

--视图
SELECT count(VIEW_NAME) FROM user_views;
--表
SELECT count(*) FROM user_tables;
--索引
SELECT count(*) FROM user_indexes;

(四)删除索引单独索引

--删除当前用户的索引
BEGIN
   FOR idx IN (
      SELECT index_name 
      FROM user_indexes
      WHERE index_type != 'LOB'
   ) 
   LOOP
      EXECUTE IMMEDIATE 'DROP INDEX ' || idx.index_name;
   END LOOP;
END;
/
--重新导入
 nohup impdp system/[password]@10.153.x.x:1521/[PDBName]  DUMPFILE=dmpname_xxx.dmp DIRECTORY=dump_dir logfile=xx_INDEX_dump_dir_EXP$(date +'%Y-%m-%d_%H-%M-%S').log SCHEMAS=[SCHEMASName]  PARALLEL=8  INCLUDE=INDEX   TABLE_EXISTS_ACTION=REPLACE   >XX_INDEX_nohup_$(date +'%Y-%m-%d_%H-%M-%S').log 2>&1 &

(五)删除pdb重新再来(谨慎操作)

如果导入碰到了一些问题,需要重新再来,可以删除pdb了重新导入,但是谨慎使用,并且再已知风险情况下执行

--关闭pdb
sqlplus / as sysdb
alter session set container=[PDBName];
ALTER PLUGGABLE DATABASE [PDBName] CLOSE IMMEDIATE;
exit
--删除
sqlplus / as sysdb
DROP PLUGGABLE DATABASE [PDBName] INCLUDING DATAFILES;

(六) 导入报错无法扩展表空间“Resumable error: ORA-01691: by 8192 in tablespace USERS”

导入过程中报错无法扩展表空间,前面创建表空间已经提到过表空间由于受最大块数(DB_BLOCK_SIZE)限制,无法创建较大文件,普通表空间到达一定大小左右就需要重新添加数据文件。所以解决这个问题需要新添加一个表空间文件

--查看表空间使用
SELECT tablespace_name, 
       SUM(bytes) / 1024 / 1024 / 1024 AS "总大小(GB)", 
       SUM(bytes) / 1024 / 1024 / 1024 - SUM(free_space) / 1024 / 1024 / 1024 AS "已用大小(GB)",
       SUM(free_space) / 1024 / 1024 / 1024 AS "剩余大小(GB)"
FROM (
    SELECT tablespace_name, bytes, 0 AS free_space
    FROM dba_data_files
    UNION ALL
    SELECT tablespace_name, 0 AS bytes, bytes AS free_space
    FROM dba_free_space
)
GROUP BY tablespace_name;
--新添加数据文件扩容表空间
ALTER TABLESPACE [TABLESPACEName] ADD DATAFILE '[/path/to/datafile2.dbf]' SIZE 20G AUTOEXTEND ON NEXT 1G MAXSIZE 50G;
--需要注意的是扩容的新文件文件名不能和之前一样,另外建议创建的路径和之前一致!!!
--可以通过下面语句查询出之前的表空间路径
SELECT FILE_NAME, TABLESPACE_NAME FROM DBA_DATA_FILES WHERE TABLESPACE_NAME = '[TableName]';
posted @ 2024-12-12 11:24  老实人张彡  阅读(12)  评论(0编辑  收藏  举报