一、SQLPlus数据迁移概述
SQLPlus作为Oracle数据库的命令行工具,在数据迁移场景中具有独特优势:轻量、稳定、可自动化。本文详细介绍在Debian系统上使用SQLPlus完成数据迁移的完整流程。
1.1 迁移场景分类
| 迁移类型 | 说明 | 推荐工具 |
|---|---|---|
| 同版本迁移 | 11g→11g, 19c→19c | EXP/IMP, EXPDP/IMPDP |
| 跨版本升级 | 11g→19c, 12c→21c | EXPDP/IMPDP |
| 跨平台迁移 | Linux→Windows, Debian→RHEL | EXPDP/IMPDP |
| 部分数据迁移 | 单表/多表迁移 | SPOOL, INSERT SELECT |
| 实时同步 | 主从复制 | DB_LINK + 物化视图 |
1.2 SQLPlus在迁移中的角色
SQLPlus主要用于:
– 执行导出/导入脚本
– 验证迁移结果
– 执行数据校验
– 处理迁移后清理
二、迁移前准备
2.1 环境检查
# 检查Oracle客户端版本
sqlplus -v
# 检查数据库版本
sqlplus / as sysdba
SELECT * FROM v$version;
# 检查字符集
SELECT * FROM nls_database_parameters WHERE parameter LIKE '%CHARACTERSET%';
# 检查可用空间
df -h /u01
2.2 创建迁移目录
-- 创建Oracle目录对象
CREATE DIRECTORY migration_dir AS '/tmp/migration';
GRANT READ, WRITE ON DIRECTORY migration_dir TO scott;
-- 查看已有目录
SELECT * FROM dba_directories;
# Debian上创建实际目录
sudo mkdir -p /tmp/migration
sudo chown oracle:oinstall /tmp/migration
sudo chmod 775 /tmp/migration
2.3 空间预估
-- 估算数据量
SELECT owner, segment_type, SUM(bytes)/1024/1024 AS size_mb
FROM dba_segments
WHERE owner = 'SCOTT'
GROUP BY owner, segment_type;
-- 查看表空间使用率
SELECT tablespace_name,
ROUND(used_space * 100 / total_space, 2) AS used_pct
FROM (
SELECT tablespace_name,
SUM(bytes) AS used_space,
(SELECT SUM(bytes) FROM dba_data_files WHERE tablespace_name = a.tablespace_name) AS total_space
FROM dba_segments a
GROUP BY tablespace_name
);
三、数据导出方法
3.1 使用EXP传统导出
# 全库导出
exp system/password@orcl FULL=y FILE=/tmp/migration/full.dmp LOG=/tmp/migration/full.log
# 按用户导出
exp scott/tiger@orcl OWNER=scott FILE=/tmp/migration/scott.dmp LOG=/tmp/migration/scott.log
# 按表导出
exp scott/tiger@orcl TABLES=emp,dept FILE=/tmp/migration/tables.dmp LOG=/tmp/migration/tables.log
# 带条件导出
exp scott/tiger@orcl TABLES=emp QUERY=\"WHERE sal > 3000\" FILE=/tmp/migration/emp_high_sal.dmp
EXP参数说明:
| 参数 | 说明 |
|---|---|
| FULL=y | 全库导出 |
| OWNER=scott | 按用户导出 |
| TABLES=emp,dept | 按表导出 |
| FILE= | 导出文件路径 |
| LOG= | 日志文件路径 |
| COMPRESS=y | 压缩导出 |
| DIRECT=y | 直接路径导出(更快) |
3.2 使用EXPDP数据泵导出
EXPDP是Oracle 10g+推荐的导出工具,性能更优:
# 按用户导出
expdp scott/tiger DIRECTORY=migration_dir DUMPFILE=scott.dmp LOGFILE=scott.log SCHEMAS=scott
# 全库导出
expdp system/password DIRECTORY=migration_dir DUMPFILE=full_%U.dmp LOGFILE=full.log FULL=y PARALLEL=4
# 按表导出
expdp scott/tiger DIRECTORY=migration_dir DUMPFILE=tables.dmp LOGFILE=tables.log TABLES=emp,dept
# 带条件导出
expdp scott/tiger DIRECTORY=migration_dir DUMPFILE=emp_high_sal.dmp LOGFILE=emp_high_sal.log TABLES=emp QUERY=\"WHERE sal > 3000\"
# 预估导出大小
expdp scott/tiger ESTIMATE_ONLY=y SCHEMAS=scott
EXPDP高级参数:
| 参数 | 说明 |
|---|---|
| PARALLEL=4 | 并行度 |
| COMPRESSION=ALL | 压缩数据 |
| ENCRYPTION=ALL | 加密导出 |
| FILESIZE=1G | 分割文件大小 |
| %U | 多文件通配符 |
| INCLUDE=TABLE | 只导出表 |
| EXCLUDE=INDEX | 排除索引 |
3.3 使用SPOOL导出为SQL脚本
适合小数据量迁移:
-- 生成INSERT脚本
SPOOL /tmp/migration/emp_insert.sql
SET FEEDBACK OFF
SET PAGESIZE 0
SET LINESIZE 32767
SET TRIMSPOOL ON
SET HEADING OFF
SET ECHO OFF
SELECT 'INSERT INTO emp (empno, ename, job, sal) VALUES (' ||
empno || ', ''' || ename || ''', ''' || job || ''', ' || sal || ');'
FROM emp;
SPOOL OFF
3.4 使用UTL_FILE导出为CSV
-- 创建PL/SQL脚本导出CSV
DECLARE
fHandle UTL_FILE.FILE_TYPE;
CURSOR c_emp IS SELECT empno, ename, sal FROM emp;
BEGIN
fHandle := UTL_FILE.FOPEN('MIGRATION_DIR', 'emp.csv', 'W');
UTL_FILE.PUT_LINE(fHandle, 'empno,ename,sal');
FOR r IN c_emp LOOP
UTL_FILE.PUT_LINE(fHandle, r.empno || ',' || r.ename || ',' || r.sal);
END LOOP;
UTL_FILE.FCLOSE(fHandle);
END;
/
四、数据导入方法
4.1 使用IMP传统导入
# 全库导入
imp system/password@orcl FULL=y FILE=/tmp/migration/full.dmp LOG=/tmp/migration/full_imp.log
# 按用户导入
imp scott/tiger@orcl FROMUSER=scott TOUSER=scott FILE=/tmp/migration/scott.dmp LOG=/tmp/migration/scott_imp.log
# 按表导入
imp scott/tiger@orcl TABLES=emp,dept FILE=/tmp/migration/tables.dmp LOG=/tmp/migration/tables_imp.log
# 忽略创建用户错误
imp scott/tiger@orcl FULL=y IGNORE=y FILE=/tmp/migration/full.dmp
4.2 使用IMPDP数据泵导入
# 按用户导入
impdp scott/tiger DIRECTORY=migration_dir DUMPFILE=scott.dmp LOGFILE=scott_imp.log SCHEMAS=scott
# 全库导入
impdp system/password DIRECTORY=migration_dir DUMPFILE=full_%U.dmp LOGFILE=full_imp.log FULL=y PARALLEL=4
# 修改用户名导入
impdp system/password DIRECTORY=migration_dir DUMPFILE=scott.dmp LOGFILE=scott_imp.log REMAP_SCHEMA=scott:new_scott
# 修改表空间
impdp system/password DIRECTORY=migration_dir DUMPFILE=scott.dmp LOGFILE=scott_imp.log REMAP_TABLESPACE=users:new_tablespace
# 只导入结构
impdp scott/tiger DIRECTORY=migration_dir DUMPFILE=scott.dmp LOGFILE=scott_imp.log CONTENT=METADATA_ONLY
IMPDP高级参数:
| 参数 | 说明 |
|---|---|
| REMAP_SCHEMA | 修改用户名 |
| REMAP_TABLESPACE | 修改表空间 |
| REMAP_DATA | 修改数据值 |
| TABLE_EXISTS_ACTION | 表存在时的操作(APPEND/REPLACE/SKIP/TRUNCATE) |
| CONTENT=DATA_ONLY | 只导入数据 |
| PARALLEL=4 | 并行导入 |
4.3 使用SQL*Loader加载数据
适合从CSV/文本文件导入:
-- 创建控制文件 emp.ctl
LOAD DATA
INFILE '/tmp/migration/emp.csv'
APPEND
INTO TABLE emp
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
(empno, ename, job, sal)
# 执行SQL*Loader
sqlldr scott/tiger CONTROL=/tmp/migration/emp.ctl LOG=/tmp/migration/emp.log
# 查看坏文件
cat /tmp/migration/emp.bad
五、跨平台迁移
5.1 字节序(Endian)处理
-- 查看平台字节序
SELECT platform_name, endian_format
FROM v$transportable_platform
WHERE platform_name LIKE '%Linux%';
-- 转换字节序(如有需要)
-- 在源平台执行:
CONVERT DATAFILE '/u01/oradata/users01.dbf'
FROM PLATFORM 'Linux x86 64-bit'
TO PLATFORM 'Microsoft Windows x86 64-bit';
5.2 字符集转换
-- 查看源库字符集
SELECT value FROM nls_database_parameters
WHERE parameter = 'NLS_CHARACTERSET';
-- 如果字符集不同,EXPDP会自动转换
-- 或手动指定:
expdp ... NLS_CHARACTERSET=AL32UTF8
5.3 跨平台迁移步骤
1. 在源库使用EXPDP导出
│
2. 传输dump文件到目标服务器(scp/rsync)
│
3. 在目标库创建用户和表空间
│
4. 使用IMPDP导入(可REMAP_SCHEMA/TABLESPACE)
│
5. 验证数据完整性
│
6. 编译无效对象
│
7. 收集统计信息
六、迁移后验证
6.1 对象计数验证
-- 比较源库和目标库的对象数量
SELECT object_type, COUNT(*)
FROM dba_objects
WHERE owner = 'SCOTT'
GROUP BY object_type;
-- 比较表行数
SELECT table_name, num_rows
FROM dba_tables
WHERE owner = 'SCOTT';
6.2 数据校验
-- 校验和验证
SELECT /*+ FULL(a) */ SUM(DBMS_UTILITY.GET_HASH_VALUE(empno||ename||sal, 0, POWER(2,32)-1))
FROM emp;
-- 在源库和目标库分别执行,比较结果
6.3 编译无效对象
-- 查看无效对象
SELECT owner, object_name, object_type
FROM dba_objects
WHERE status = 'INVALID' AND owner = 'SCOTT';
-- 编译无效对象
@$ORACLE_HOME/rdbms/admin/utlrp.sql
-- 或手动编译
ALTER PACKAGE scott.pkg_emp COMPILE;
ALTER VIEW scott.v_emp COMPILE;
七、性能优化
7.1 EXPDP/IMPDP并行优化
# 使用并行+大文件大小
expdp system/password DIRECTORY=migration_dir \
DUMPFILE=full_%U.dmp \
FILESIZE=2G \
PARALLEL=4 \
SCHEMAS=scott
# 对应IMPDP也使用并行
impdp system/password DIRECTORY=migration_dir \
DUMPFILE=full_%U.dmp \
PARALLEL=4 \
SCHEMAS=scott
7.2 禁用约束和索引
-- 导入前禁用约束
SELECT 'ALTER TABLE ' || table_name || ' DISABLE CONSTRAINT ' || constraint_name || ';'
FROM user_constraints
WHERE constraint_type IN ('P', 'R');
-- 导入后启用约束
SELECT 'ALTER TABLE ' || table_name || ' ENABLE CONSTRAINT ' || constraint_name || ';'
FROM user_constraints
WHERE constraint_type IN ('P', 'R');
7.3 调整SGA和PGA
-- 增加SGA_TARGET以加速导入
ALTER SYSTEM SET SGA_TARGET=4G SCOPE=SPFILE;
ALTER SYSTEM SET PGA_AGGREGATE_TARGET=2G SCOPE=SPFILE;
-- 重启数据库生效
SHUTDOWN IMMEDIATE;
STARTUP;
八、常见问题解答
Q1: EXP导出报错”ORA-01555: snapshot too old”?
A: 增加UNDO表空间大小:
ALTER TABLESPACE undotbs1 RESIZE 4G;
-- 或
ALTER SYSTEM SET UNDO_RETENTION=3600 SCOPE=BOTH;
Q2: IMPDP导入时报”ORA-01658: unable to create INITIAL extent”?
A: 表空间空间不足,扩展表空间:
ALTER TABLESPACE users ADD DATAFILE '/u01/oradata/users02.dbf' SIZE 1G;
Q3: 如何只导出表结构不导出数据?
A: 使用CONTENT=METADATA_ONLY参数:
expdp scott/tiger DIRECTORY=migration_dir DUMPFILE=scott_meta.dmp CONTENT=METADATA_ONLY SCHEMAS=scott
Q4: 跨版本迁移(如11g→19c)需要注意什么?
A:
1. 使用EXPDP/IMPDP(不支持EXP/IMP跨大版本)
2. 源库使用低版本兼容参数导出
3. 目标库创建兼容的字符集
4. 测试应用SQL在新版本的兼容性
九、总结
在Debian上使用SQLPlus进行Oracle数据迁移,核心是掌握EXPDP/IMPDP工具。关键步骤包括:迁移前准备(环境检查、空间预估、目录创建)、数据导出(EXPDP多种模式)、数据导入(IMPDP灵活映射)、跨平台处理(字节序、字符集)、迁移后验证(对象计数、数据校验)。
最佳实践建议:
1. 优先使用EXPDP/IMPDP(性能更优)
2. 大数据库使用并行+分割文件
3. 迁移前在测试环境验证
4. 迁移后务必进行数据校验
注:本文基于Oracle 19c + Debian 12环境整理,适用于Oracle 11g及以上版本。