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]';