1.基本信息
源库 | 目标库 | |
---|---|---|
IP | 192.168.0.6 | 192.168.0.8 |
数据库版本 | 19C | 19C |
2.提前作业部分
以导出导入方式迁移数据库需要预约停机,为节省停机时间,可以提前做一部分工作。
2.1.创建表空间
表空间名和大小最好和源库一样,停机作业当天再检查一遍,防止中间源库扩充表空间而目标库没有扩。
2.2.创建 Role 和 Profile
提前把 role 和 profile 创建好,避免导入 owner 报错。
2.3.安装 ogg 软体
源库有 ogg ,提前安装好 ogg
create tablespace ggs_data datafile '/data/monkey/ggs_data01.dbf' size 1g;
create user ogg identified by ogg default tablespace ggs_data temporary tablespace temp quota unlimited on ogg;
grant connect, resource,dba TO ogg;
dblogin userid ogg,password ogg
add checkpointtable ogg.checkpointtab
2.4.提前建立 OS 排程脚本
execute_oracle_procedure.sh
3.保存失效对象
@TOSOURCE 代表的是在目标库建立的指向源库的 DBLINK,在目标库执行。
create table monkey.invalid_objects as select owner,object_name,object_type From dba_objects@TOSOURCE where status = 'INVALID';
4.锁账号
源库锁账号,防止新数据进入,根据实际情况锁,例如你已经知道要导哪些 OWNER 了,直接锁定即可。
-- 这个 sql 是在目标库执行的,得到的脚本在源库执行锁账号
SELECT 'ALTER USER ' || USERNAME || ' ACCOUNT LOCK;'
FROM (SELECT USERNAME FROM dba_users@TOSOURCE
MINUS
SELECT USERNAME FROM dba_users)
WHERE USERNAME NOT IN ('OGG', 'MONITOR');
5.停 OS 排程和数据库 JOB
源库停 OS 排程和数据库 JOB,防止新数据进入。
# 停 OS 排程
crontab -l > crontab_backup.txt
crontab -l | sed '/^$/! s/^/#/' | crontab -
scp crontab_backup.txt 192.168.0.8:`pwd`
-- 记录下来 JOB_QUEUE_PROCESSES 的值,后面作业完源库需要改回去
show parameter JOB_QUEUE_PROCESSES;
alter system set JOB_QUEUE_PROCESSES=0;
6.停 OGG
源库停 OGG,rep1 是应用进程,ext1 是抽取进程,pub1 是传送进程。把 info 信息记录下来,后面新增 OGG 时需要用到。
stop rep1
stop ext1
stop pub1
info rep1
info ext1
info ext1
7.杀 session
源库杀 session,把自己排除,别把自己的会话也杀了。
select 'alter system kill session '''||sid||','||serial#||''' immediate;'From v$session where type='USER' and username <>'MONKEY';
8.导出
源库根据实际情况导出(按照自己的 owner 清单)
SELECT LISTAGG (USERNAME, ',') WITHIN GROUP (ORDER BY USERNAME) AS result
FROM (SELECT USERNAME FROM dba_users@TOSOURCE
MINUS
SELECT USERNAME FROM dba_users)
WHERE USERNAME NOT IN ('OGG', 'MONITOR');
create directory monkey as '/data/monkey/20250420';
alter system set parallel_max_servers=30;
cd /data/monkey/20250420
vi expdp_monkey_schemas.par
directory=monkey
SCHEMAS=SAILY,JOHN,HR,MONKEY
dumpfile=expdp_monkey_schemas_%U.dmp
filesize=6G
CONTENT=ALL
parallel=10
COMPRESSION=ALL
logfile=expdp_monkey_schemas.log
expdp monkey/monkey PARFILE=expdp_monkey_schemas.par
scp expdp_monkey_schemas_*.dmp oracle@192.168.0.8:/data/monkey/20250420
9.导入结构
目标库导入结构
create directory monkey as '/data/monkey/20250420';
alter system set parallel_max_servers=30;
cd /data/monkey/20250420
-- monkey是我的管理账号,目标库我创建了,但是为了保持一致,还是准备从源库导入
sqlplus / as sysdba
drop user monkey cascade;
# 可以执行两次,防止第一次用户不存在导致导入缺失
impdp \'/ as sysdba\' directory=monkey dumpfile=expdp_monkey_schemas_%U.dmp CONTENT=METADATA_ONLY EXCLUDE=STATISTICS parallel=10 logfile=impdp_expdp_monkey_schemas.log
# 下面的语句也是为了防止用户不存在导致的赋权缺失
impdp \'/ as sysdba\' directory=monkey dumpfile=expdp_monkey_schemas_%U.dmp parallel=10 INCLUDE=GRANT logfile=impdp_GRANT_monkey_schemas.log
结构导入之后,要进行比对,别导少了。
DECLARE
-- 定义一个嵌套表类型
TYPE OwnerArray IS TABLE OF VARCHAR2(30);
-- 初始化你的owner列表
owners OwnerArray := OwnerArray('MONKEY', 'SAILY', 'JOHN','HR');
v_owner VARCHAR2(30);
v_count_local NUMBER;
v_count_remote NUMBER;
BEGIN
-- 遍历数组
FOR i IN owners.FIRST .. owners.LAST LOOP
v_owner := owners(i);
-- 查询本地(B库)对象数
SELECT COUNT(*)
INTO v_count_local
FROM dba_objects
WHERE owner = v_owner;
-- 查询远程(A库,通过DBLINK)对象数
SELECT COUNT(*)
INTO v_count_remote
FROM dba_objects@TOSOURCE -- <--- 替换成你的DBLINK名字
WHERE owner = v_owner;
-- 比较并输出结果
IF v_count_local = v_count_remote THEN
DBMS_OUTPUT.PUT_LINE('Owner ' || v_owner || ' OK: ' || v_count_local || ' objects.');
ELSE
DBMS_OUTPUT.PUT_LINE('Owner ' || v_owner || ' DIFFERENT! Local=' || v_count_local || ', Remote=' || v_count_remote);
END IF;
END LOOP;
END;
/
10.禁用触发器和外键
目标库禁用触发器和外键,防止数据导入时报错。
-- 禁用外键
select 'ALTER TABLE '||OWNER||'.'||TABLE_NAME||' DISABLE CONSTRAINT '||CONSTRAINT_NAME||';' from DBA_CONSTRAINTS where constraint_type='R' and owner in ('MONKEY', 'SAILY', 'JOHN','HR');
-- 禁用触发器
select 'ALTER TRIGGER '||OWNER||'.'||TRIGGER_NAME||' DISABLE;' from dba_triggers where TABLE_OWNER in ('MONKEY', 'SAILY', 'JOHN','HR');
11.导入数据
目标库导入数据,注意归档,TEMP 表空间,UNDO 表空间,在线日志。
# 把 undo 保留时间改小,防止 undo 不足
alter system set undo_retention=60;
impdp \'/ as sysdba\' directory=monkey dumpfile=expdp_monkey_schemas_%U.dmp CONTENT=DATA_ONLY parallel=10 logfile=impdp_DATA_ONLY_monkey_schemas.log;
# 把之前修改的参数改回去
alter system set undo_retention=900;
alter system set parallel_max_servers=0;
12.启用外键和触发器
select 'ALTER TABLE '||OWNER||'.'||TABLE_NAME||' ENABLE CONSTRAINT '||CONSTRAINT_NAME||';' from DBA_CONSTRAINTS where constraint_type='R' and owner in ('MONKEY', 'SAILY', 'JOHN','HR');
select 'ALTER TRIGGER '||OWNER||'.'||TRIGGER_NAME||' ENABLE;' from dba_triggers where TABLE_OWNER in ('MONKEY', 'SAILY', 'JOHN','HR');
13.解锁账号
源库导出结构的时候账号是锁定状态,所以目前目标库的账号也是锁定状态,要解锁。
ALTER USER MONKEY ACCOUNT UNLOCK;
ALTER USER SAILY ACCOUNT UNLOCK;
14.关闭 OGG 传送进程
在第6步停 OGG 的时候,有一个 rep1 的应用进程,这个进程应用的 trail 文件来自于 192.168.0.10,关闭 192.168.0.10上的传送进程
stop e_monkey
stop p_monkey
15.处理 IP
因为要保持迁移后程序不需要修改 TNS ,因此我们要把源库和目标库的 IP 调换。
涉及到以下部分:
源库和目标库的 listener.ora文件
源库和目标库的 /etc/hosts 文件
如果有高可用,需要修改高可用的 IP 资源
16.OGG 处理
目标库目前是没有 OGG 进程的,因此要新增
16.1. 目标库应用进程
对于目标库上面的应用进程,只需要把源库参数文件和 trail 文件 SCP 过来,新增即可。
# 把参数文件和 trail 文件 scp 过来
scp -r monkey 192.168.0.6:`pwd`
scp ./dirprm/rep1.prm 192.168.0.6:/data/ogg/dirprm
# 添加应用进程
add replicat rep1,exttrail ./monkey/r1,checkpointtable ogg.checkpointtab
# 这里的324和313206553就是第6步停 rep1 时候 info 得到的
alter replicat rep1,EXTSEQNO 324,EXTRBA 313206553
start rep1 NOFILTERDUPTRANSACTIONS
16.2.目标库抽取传送进程
对于目标库上的抽取进程和传送进程,把源库的参数文件 SCP 过来,新增进程。注意,此时会在 192.168.0.12 (应用目标库抽取的 trail 文件的主机)上的 OGG需要重新指定 exttrail
首先停止 192.168.0.12 上的应用进程
stop r_monkey
目标库(192.168.0.8 )新增抽取和传送进程
dblogin userid ogg,password ogg
add extract ext1,integrated tranlog,begin now
register extract ext1 database
# 注意 ext1.prm 中的 EXTTRAIL 参数要修改为e2,不要用原来的e1
ADD EXTTRAIL ./monkey/e2, EXTRACT bd_ext, MEGABYTES 100
add extract pub1, exttrailsource ./monkey/e2
# 注意 pub1.prm 中的 RMTTRAIL 参数要修改为r2,不要用原来的r1
add rmttrail ./monkey/r2, extract pub1
start ext1
start pub1
16.3.应用目标库传送过来trail文件的应用进程
应用目标库抽取的 trail 文件的主机(192.168.0.12 )修改应用进程
ALTER REPLICAT r_monkey, EXTTRAIL ./monkey/r2, EXTSEQNO 0, EXTRBA 0
start monkey
16.4.开启抽取和传送进程
开启 192.168.0.10(即目标库 rep1 应用 trail文件来源主机) 上的抽取和传送进程
start e_monkey
start p_monkey
17.新建OS排程
目标库目前是没有 OS 排程的,利用从源库传送过来的 crontab 备份文件进行恢复。如果有高可用的话,每个节点都要执行。
cd ~
crontab crontab_backup.txt
crontab crontab_backup.txt
18.检查 DBLINK 及其连通性
把源库的 tnsnames.ora 文件 SCP 到目标库
scp tnsnames.ora 192.168.0.8:`pwd`
19.文件比对
如果有高可用,需要确保每个节点的 tnsnames.ora listener.ora spfile orapwd 文件一样。
20.全库编译
全库编译后,与第3步保存的失效对象进行对比
cd $ORACLE_HOME/rdbms/admin
@utlrp.sql
21.全库收集统计信息
BEGIN
DBMS_STATS.gather_database_stats;
END;
/
22.其他
如果源库还用,需要关闭并行,改回 JOB_QUEUE_PROCESSES 和 parallel_max_servers 参数,解锁账号。
目标库测试 OGG 应用是否正常(增删一笔试试)
目标库看 OS 排程执行是否正常,是否有执行日志产生
目标库看是否有失效的索引
目标库的监控是否安装,是否正常
目标库的备份配置是否正常,归档目录是否足够,归档删除排程是否正常,最好做一次全备。