Oracle 11g 到 19C DBUA 升级运维指导与 RMAN 避坑

发布时间:2026/11/4 7:38:04
Oracle 11g 到 19C DBUA 升级运维指导与 RMAN 避坑

简介:《Oracle 11g 到 19C 数据库升级详尽指导手册》面向具备一定运维经验的数据库管理员,围绕使用 DBUA 将 Oracle 11g 安全迁移至 19C 的维护场景展开,重点解决升级前备份恢复、版本路线确认、环境准备与升级后配置调整等问题。资源包仅含 1 个 PDF 文件,大小约 3.18MB,便于集中查阅完整升级流程与关键注意事项。已有 1361 人学习,说明其在 DBA 升级实践中具有一定参考价值。内容覆盖单机环境通过 DBUA 升级的完整思路,包括源库与目标库规划、RMAN 备份恢复到测试环境、归档追平、直接与间接升级路线、Linux 7 最低系统要求,以及图形化和静默方式的操作要点。文中还强调检查脚本生成的日志与警告,并给出多个故障处理方案,读者可据此梳理从 11g 到 19C 的操作顺序、风险点和排错路径,提升升级过程的可控性与回退保障。

1. 一条被 11g 停更逼出来的升级路线

去年给一个业务系统做硬件置换,源库还停在 Oracle 11g 11.2.0.4,补丁通道早就没有可打的东西了,运维指南里那句「官方建议升到 19C」被翻出来看了好几遍。真到动手才发现,DBUA 只是最后那一下点击,前面 RMAN 恢复、参数改写、preupgrade 修数,任何一步做浅了,19C 就起不来。这份 Oracle 19C DBUA 升级 Oracle 11g 数据库升级运维指导手册,把 11g 单机升 19C 的过程拆成了一串能照着敲的步骤,从备份恢复到 DBUA 执行再到升级后检查,中间的报错记录也一并留着。适合手上还压着 11g 库、需要在不影响生产的前提下演练一遍升级的 DBA。

2. 升级前的硬性门槛:版本矩阵、主机与 ORACLE_HOME 规划

升级失败的项目,十有八九不是败在 DBUA 点下去那一刻,而是败在动手之前对版本和主机的判断上。11g 停更之后,很多人第一反应是「装个 19c 软件,跑 DBUA 就完了」,结果第一步就卡在操作系统版本上。这一章把前置条件摊开讲,先把不可能的路排掉,再谈具体操作。

2.1 直升级矩阵与间接升级路径

19C 对源库版本是挑剔的,不是所有 11g 都能一步到位。源库版本落在 11.2.0.4 及以上、12.1.0.2、12.2.0.1、18.1 这几个点位上,才能直接 DBUA 升到 19.x;落在更早的小版本,必须先补到中间版本。这条线不是建议,是硬限制,DBUA 的预检查会直接拦下来。

源库版本升级路径目标版本
11.2.0.4 及以上直接升级19.x
12.1.0.2 / 12.2.0.1 / 18.1直接升级19.x
11.2.0.1 / 11.2.0.2 / 11.2.0.3先补到 11.2.0.419.x
11.1.0.6 / 11.1.0.7先补到 11.2.0.419.x
10.2.0.2 ~ 10.2.0.5先到 11.2.0.4 或 12.1.0.219.x
10.1.0.5先到 11.2.0.4 或 12.1.0.219.x
9.2.0.8 及更早先到 11.2.0.419.x
12.1.0.1先到 12.1.0.2 或 12.2.0.119.x

先跑一条 SQL 把源库的版本钉死,不要靠记忆:

-- 在源库 11g 上执行,确认四段式版本号与补丁集 SELECT banner_full FROM v$version; -- 输出形如:Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production -- 第四位是 PSU 补丁号,前四位 11.2.0.4 才是升级资格线

参数说明:v$version里的banner_full比banner更完整,能看到具体的 Release 和补丁信息;如果只看到11.2.0.4.0这样的四段号,说明是基础版,后面是否打过 PSU 要看dba_registry_sqlpatch。11.2.0.1 到 11.2.0.3 的库,中间必须插一次 11.2.0.4 的升级,这一步没有捷径,DBUA 不会帮你跨版本补丁。

2.2 主机版本、ORACLE_HOME 与实例命名的三处坑

19C 对操作系统的支持底线是 Linux 7。这一条卡掉了大量老环境:11g 时代的服务器多数跑在 Linux 6 上,而 19c 软件在 Linux 6 上根本装不起来,不是装完报错,是安装程序直接判定不支持。遇到这种情况,路子只有一条——准备一台 Linux 7 的新主机,装好 19c 软件,把生产库用 RMAN 恢复到这台机器上再升级。生产库原样保留,升级失败随时切回去,这是整个方案里最值钱的一条设计。

目标端的 ORACLE_HOME 必须和源库分开,不能覆盖。参考环境里源库 home 是/u02/app/oracle/product/11.2.0/db,19c home 是/u01/app/oracle/product/19.14.0/db_1,两个目录树物理隔离。顺手提一句,原始环境表里两行的 ORACLE_HOME 和数据库版本是对调的,照着抄会把 19c 软件装进 11g 的目录里,这种表里的笔误在实际文档里非常常见,看到版本号和 home 对不上,以版本号为准。

再一个是实例命名。恢复过来的库如果db_name和db_unique_name跟源库完全一样,而两台机器又都在同一个网络里,监听注册、Data Guard、归档传输都会打架。常见做法是保留db_name不变,把db_unique_name改成一个新名字,比如源库叫bsoft,恢复出来的演练库叫bsoftsb,后面所有控制文件路径、归档路径、服务名都跟着这个 unique name 走。

2.3 preupgrade.jar:把问题在升级前一次性挖出来

19c 的 home 下自带升级预检查工具preupgrade.jar,位置在$ORACLE_HOME/rdbms/admin/。这个 jar 要在源库上跑,但用 19c home 里的 java 执行更稳妥,避免 11g 自带 JDK 版本过低跑不起来。

# 在源库主机上执行,ORACLE_SID 指向待升级的 11g 实例 export ORACLE_SID=bsoft export ORACLE_HOME=/u02/app/oracle/product/11.2.0/db # 用 19c home 下的 java 跑 19c 的 preupgrade.jar /u02/app/oracle/product/19.14.0/db_1/jdk/bin/java \ -jar /u02/app/oracle/product/19.14.0/db_1/rdbms/admin/preupgrade.jar \ FILE TEXT DIR /home/oracle/preupgrade # 执行完检查产物 ls -l /home/oracle/preupgrade # preupgrade.log 预检查明细,逐条列出阻塞项和建议 # preupgrade_fixups.sql 升级前必须在源库执行的修复脚本 # postupgrade_fixups.sql 升级完成后需要执行的收尾脚本

参数说明:FILE TEXT表示输出纯文本报告,比默认的 XML 好读;DIR指定输出目录,必须提前建好并有 oracle 用户写权限。跑完之后先别急着执行 fixup,把preupgrade.log从头到尾读一遍,重点看三类内容——标了ERROR的阻塞项必须先处理,标了WARNING的要看是否影响业务,还有一类是「Desupported」组件清单,比如某些老版本里的 OLAP、OWB、AMD 之类组件在 19c 里已经不再支持,这些组件如果还在dba_registry里挂着,DBUA 升级会直接失败。

处理完阻塞项,再执行preupgrade_fixups.sql,这个脚本会做几件事:创建升级用的辅助表空间、清理回收站、把一些在 19c 里不兼容的参数记下来、收集字典统计信息。执行完再跑一次 preupgrade.jar 确认阻塞项清零,这一步不能省,我见过有人图省事跳过二次检查,DBUA 跑到一半报组件错误,回退重来花的时间是检查的十倍。

3. 用 RMAN 把生产库搬到测试机:参数文件、控制文件、catalog 三段式恢复

升级演练的第一步不是升级,是把生产库完整地复制一份到目标机器上。这个过程用 RMAN 做,分三段:先恢复参数文件把实例拉起来,再恢复控制文件把备份集认出来,最后 restore 数据文件、recover 追归档。三段的顺序不能乱,乱了就会遇到「找不到控制文件」或者「备份片无法识别」这类问题。

3.1 恢复 spfile 与 pfile 改写

目标机上还没有任何实例,直接startup nomount会因为找不到参数文件失败。稳妥的做法是先写一个只有一行内容的最小 pfile,把实例拉到 nomount,再从备份片里恢复真正的 spfile。

# 目标机,先用最小 pfile 拉起 nomount echo "db_name=bsoft" > /home/oracle/init_temp.ora rman target /
# RMAN 会话内 startup nomount pfile='/home/oracle/init_temp.ora'; # 从备份片里恢复 spfile,备份片路径来自源库的 rman 备份 restore spfile from '/hisbak/spfile_BSOFT_562120512_20220830_40444.ora'; # 用恢复出来的 spfile 生成可编辑的 pfile sql 'create pfile=''/home/oracle/pfile.ora'' from spfile'; exit;

逻辑说明:restore spfile只认备份集或备份片,不认文件系统上的 spfile 副本,所以路径要指向源库 rman 备份出来的那个文件。恢复出来的 spfile 落在$ORACLE_HOME/dbs/spfile$ORACLE_SID.ora,但它是源库的原样参数,带着源库的路径、SID、内存配置,必须改成目标机的。生成 pfile 就是为了编辑它。

改写时逐项核对,下面这段是改完之后的样子:

# /home/oracle/pfile.ora 关键参数节选,星号开头表示对所有实例生效 *.audit_file_dest='/u02/app/oracle/admin/bsoftsb/adump' *.audit_trail='NONE' *.compatible='11.2.0.4.0' *.control_files='/oradata/bsoftsb/controlfile/control01.dbf' *.db_block_size=8192 *.db_create_file_dest='/oradata' *.db_domain='' *.db_name='bsoft' *.db_recovery_file_dest='/arch' *.db_recovery_file_dest_size=200G *.db_unique_name='bsoftsb' *.diagnostic_dest='/u02/app/oracle' *.log_archive_dest_1='LOCATION=use_db_recovery_file_dest VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=bsoftsb' *.log_archive_format='%t_%s_%r.dbf' *.memory_max_target=128849018880 *.memory_target=128849018880 *.open_cursors=2000 *.pga_aggregate_target=8474591232 *.processes=6000 *.sga_max_size=68719476736 *.sga_target=68719476736 *.service_names='bsoft,bsoftsb' *.undo_tablespace='UNDOTBS1'

参数说明:audit_file_dest和diagnostic_dest必须指向目标机上真实存在且权限正确的目录,ADUMP 目录要提前用mkdir -p建好,不然实例起不来。control_files指向目标机上规划的控制文件路径,原值多半是 ASM 或源库的本地路径,不改会报ORA-00205。db_unique_name改成新名字,log_archive_dest_1和service_names里引用的名字要同步改,漏改一处归档就落到了错误的位置。内存相关的memory_target、sga_target在原环境里是 128G / 64G 的规格,目标机内存小的话必须等比下调,否则实例启动时报ORA-00845或直接被系统 OOM 干掉。

改完之后用 pfile 启动到 nomount,再从 pfile 生成目标机自己的 spfile:

-- 用改写后的 pfile 启动 startup nomount pfile='/home/oracle/pfile.ora'; -- 生成目标机自己的 spfile CREATE SPFILE='/u02/app/oracle/product/11.2.0/db/dbs/spfilebsoft.ora' FROM PFILE='/home/oracle/pfile.ora'; exit;

3.2 控制文件恢复与 catalog 加载

控制文件里记录着数据文件和归档的绝对路径,源库多半用 ASM,路径形如+DATA/bsoftsb/datafile/system.270.979224249。这些路径在目标机上不存在,直接 restore 会失败,所以要用SET NEWNAME在 restore 时把路径重定向到本地文件系统。

# 从控制文件备份片恢复,注意控制文件不能从备份集里挑,要指定具体备份片 rman target / restore controlfile from '/hisbak/BSOFT_CONT_562120512_20220830_40443.ctl'; # 挂载,让控制文件生效 sql 'alter database mount'; # 把备份目录整批注册进控制文件 catalog start with '/hisbak/';

逻辑说明:restore controlfile之后数据库处于 nomount 状态,必须alter database mount才能读控制文件里的数据文件清单。catalog start with是最关键的一步——RMAN 本身不知道/hisbak/下面那些备份片是什么、属于哪个库,catalog 相当于让 RMAN 扫描目录里的备份片头,把元数据登记进目标库的控制文件。不做这一步,后面restore database会报RMAN-06023: no backup or copy of datafile found,看起来像是备份丢了,其实是没登记。

catalog 完成之后立刻看一眼 schema,确认数据文件清单和临时文件清单都在:

RMAN> REPORT SCHEMA; # 输出片段,注意 Datafile Name 列还是 +DATA 开头的 ASM 路径 # 1 0 SYSTEM *** +DATA/bsoftsb/datafile/system.270.979224249 # 2 0 SYSAUX *** +DATA/bsoftsb/datafile/sysaux.266.979223939 # 3 0 UNDOTBS1 *** +DATA/bsoftsb/datafile/undotbs1.269.979224213 # 共 48 个数据文件、11 个临时文件

REPORT SCHEMA的输出里如果出现RMAN-06139: WARNING: control file is not current for REPORT SCHEMA,不用紧张,这是控制文件比备份片旧导致的提示,不影响后续 restore。

3.3 restore、switch 与多次 recover 追归档

恢复数据文件这一段,核心是把 ASM 路径重定向成本地路径,并指定一个时间点,避免一次拉太多归档。

rman target / run { ALLOCATE CHANNEL C1 DEVICE TYPE DISK; -- 按需开到 C16,通道数一般取 CPU 核数或磁盘数的一半 ALLOCATE CHANNEL C16 DEVICE TYPE DISK; -- 把 ASM 路径整体重定向到本地,%b 保留原文件名 SET NEWNAME FOR DATABASE TO '/oradata/BSOFTSB/datafile/%b'; SET UNTIL TIME "TO_DATE('2022-08-30:02:00:00', 'YYYY-MM-DD:HH24:MI:SS')"; RESTORE DATABASE; RELEASE CHANNEL C16; RELEASE CHANNEL C1; }

参数说明:SET NEWNAME FOR DATABASE TO '.../%b'里的%b是占位符,代表原数据文件名,这样 48 个文件不用手写 48 行。SET UNTIL TIME限制 restore 只恢复到指定时间点之前的备份,时间点设得比备份时间早一点没关系,后面可以往前追。通道数不是越多越好,16 个通道在普通 SAS 盘上已经能跑满带宽,再加反而因为争抢 I/O 变慢。

restore 完成之后必须SWITCH DATABASE TO COPY,让控制文件里的文件指针指向新恢复出来的本地副本,不 switch 的话控制文件还指着 ASM 路径,recover 会找不到文件。

rman target / SWITCH DATABASE TO COPY; run { ALLOCATE CHANNEL C1 DEVICE TYPE DISK; ALLOCATE CHANNEL C8 DEVICE TYPE DISK; SET UNTIL TIME "TO_DATE('2022-08-30:07:00:00', 'YYYY-MM-DD:HH24:MI:SS')"; RECOVER DATABASE; RELEASE CHANNEL C8; RELEASE CHANNEL C1; }

recover 可以分多次做,每次把SET UNTIL TIME往前推一段,先恢复到 02:00,再推到 07:00,再推到 12:00。这么做有两个好处:一是每段恢复完可以停下来检查有没有报错,二是归档日志是分批拷贝过来的,一次 recover 到最新时间点很可能因为归档还没到而中断。追到一半用只读方式打开看一眼,确认数据是完整的,再关掉继续追。

-- 只读打开,验证数据文件一致性 alter database open read only; -- 如果要继续追归档,必须先回到 mount shutdown abort; startup mount;

只读打开是一个很实用的检查点。数据库能 open read only,说明数据文件、redo、undo 在物理层面是一致的,至少没有块损坏。这时候可以连进去查几张关键表、跑几条统计 SQL,确认业务数据落在预期的时间点上。确认完再shutdown abort回 mount 继续追,abort在这里是安全的,因为库处于只读状态,没有任何写操作。

追到归档尽头时通常会撞上这个报错:

RMAN-03002: failure of recover command at 08/31/2022 21:40:31 RMAN-06054: media recovery requesting unknown archived log for thread 1 with sequence 25197 and starting SCN of 18157927920

RMAN-06054的意思是「我还能往前追,但缺 sequence 25197 这个归档」。这时候用list backup of archivelog from time 'sysdate-1'查一下最近备份的归档都覆盖到哪个 sequence,对照一下就知道是归档还没拷过来,还是源库那边已经删了。归档补齐了再跑一次不带SET UNTIL TIME的RECOVER DATABASE,能追到哪算哪。追到最后一个可用归档之后,把这个库做一次全备,作为升级前的基线备份,后面 DBUA 出问题可以直接回到这个点。

4. DBUA 的两条路径:图形界面关键选项与静默模式参数

恢复出来的库能正常 open read only,升级的舞台就搭好了。DBUA 提供图形和静默两种用法,图形适合第一次演练、边点边看每一步在干什么,静默适合批量或者远程没有 X11 的环境。两条路径背后跑的是同一套脚本,理解图形界面的选项,静默参数也就看懂了。

4.1 环境变量与启动前的四项确认

DBUA 的约定有点反直觉:ORACLE_HOME要指向 19c 的新 home,ORACLE_SID要指向待升级的源库 SID。它自己会去读源库的参数文件、启动到 upgrade 模式、跑升级脚本,全程用 19c 的二进制去操作 11g 的数据字典。

# 切到 oracle 用户,ORACLE_HOME 指向 19c,ORACLE_SID 指向源库 export ORACLE_BASE=/u02/app/oracle export ORACLE_HOME=/u02/app/oracle/product/19.14.0/db_1 export ORACLE_SID=bsoft export PATH=$ORACLE_HOME/bin:$PATH export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH # 确认环境变量没串 echo $ORACLE_HOME echo $ORACLE_SID # 确认源库当前状态 sqlplus -S / as sysdba <<'EOF' select instance_name, status from v$instance; select name, open_mode from v$database; EOF

启动 DBUA 之前有四项必须确认。第一,源库处于 open 状态且没有其他会话连着,DBUA 会自己 shutdown,有活跃会话会卡住。第二,归档模式已开启,log_archive_dest_1指向的目录有空间,升级过程中产生的归档量不小。第三,目标 19c home 下的rdbms/admin目录可读,DBUA 从这里取catupgrd.sql等脚本。第四,/tmp和$ORACLE_BASE/cfgtoollogs有足够空间,DBUA 的日志和中间文件都往这里写。

启动命令很简单:

# 图形模式,需要 DISPLAY 或 X11 转发 $ORACLE_HOME/bin/dbua

4.2 图形界面里真正需要动手改的五个选项

DBUA 的向导页数不少,大部分点「下一步」就行,真正影响结果的只有五处。

第一处是选择源库。如果一台机器上有多个实例,DBUA 会把它们列出来让你选,选错 SID 等于给别的库做升级。第二处是「Upgrade」还是「Move Database Files」,这里选 Upgrade。Move 是给换存储路径用的,数据文件位置在 RMAN 恢复阶段已经规划好了,不需要 DBUA 再搬一次,选了 Move 反而多一层拷贝风险。

第三处是并行升级(Parallel Upgrade)。默认开启,按 CPU 核数决定并行度。小库开不开差别不大,大库能省不少时间,但如果目标机 CPU 核数少、内存又紧,并行会加剧资源争抢,这种情况下手动调成 2 或 4 更稳。第四处是时区文件升级(Upgrade Timezone Version)。源库的时区版本如果落后于 19c 自带版本,这里勾上会顺带升级,但要注意升级时区需要额外的时间和空间,而且升级后不能降级。

第五处是 Restore Point,也就是升级前的还原点。这个必须勾。DBUA 会在升级前创建一个 guaranteed restore point,万一升级失败,一条flashback database to restore point就能把库拉回升级前的状态,比从备份恢复快一个数量级。代价是升级期间需要保留足够的闪回日志空间,db_recovery_file_dest_size要给足,一般按库大小的 20% 到 30% 预留。

向导最后会生成一份摘要,列出即将执行的操作和预检查结果。这份摘要值得花五分钟逐行看完,里面会明确写出「哪些组件将被升级」「哪些组件将被废弃」「预计耗时」。看到「预计耗时 4 小时」不要慌,这是按最慢情况估的,实际时间跟数据字典大小强相关。

4.3 静默模式:参数、日志与进度判断

没有图形环境的时候用静默模式,一条命令跑完。

# 静默升级,路径和密码按实际环境替换 $ORACLE_HOME/bin/dbua -silent \ -sid bsoft \ -oracleHome /u02/app/oracle/product/19.14.0/db_1 \ -sysDBAUserName sys \ -sysDBAPassword 'YourPassword' \ -upgradeTimezone false \ -recompile_invalid_objects true

参数说明:-sid指定待升级的源库实例名,不是 19c 的实例名;-oracleHome是 19c 的目标 home,必须和$ORACLE_HOME一致;-upgradeTimezone设成 false 表示暂时不动时区,等升级完成后再单独评估,这样做的好处是万一升级失败,回退路径更干净;-recompile_invalid_objects设成 true 让 DBUA 在升级后自动编译无效对象。不同小版本的 DBUA 参数会有细微差异,动手前先跑一次dbua -help对一遍,别直接抄别人博客里的命令。

静默模式没有进度条,判断进度只能看日志。DBUA 的日志目录在$ORACLE_BASE/cfgtoollogs/dbua/<dbname>/upgrade<时间戳>/,里面几个关键文件:

日志文件内容看什么
dbua.logDBUA 自身流程日志每一步的开始与结束、报错栈
precheck_report.html升级前检查报告阻塞项、警告项清单
catupgrd*.log数据字典升级主日志当前跑到哪个脚本、有无 ORA 错误
postupgrade*.log升级后收尾日志无效对象编译、组件状态
upgrade_summary.log升级结果汇总成功/失败、耗时、组件变更

盯进度的时候tail -f catupgrd*.log就够了,里面会一行行打印正在执行的脚本名。看到长时间没有新行输出是正常的,编译 PL/SQL 包的时候可能几分钟不吐一个字,这时候千万别以为卡死就去 kill 进程。DBUA 被强杀之后数据字典处于半升级状态,恢复起来比从头再来麻烦得多。

4.4 DBUA 内部到底做了什么

理解内部步骤,出问题才知道停在哪。DBUA 大致按这个顺序走:先跑一遍自己的预检查,检查内容包括源库版本、组件兼容性、表空间空间、无效对象数量、参数兼容性;检查通过后创建 restore point;然后shutdown immediate,用 19c 的二进制startup upgrade打开源库;接着执行catupgrd.sql,这个脚本会依次跑catupgrd系列的子脚本,把数据字典从 11.2.0.4 的版本升到 19.x;字典升完之后编译无效对象、跑utlupp相关的收尾、更新组件版本;最后shutdown再正常startup,库就以 19c 的身份打开了。

如果中途意外中断,先看catupgrd*.log最后执行到哪个脚本,再决定是重新跑 DBUA 还是手工续做。手工续做的标准姿势是用 19c 的二进制startup upgrade,然后直接跑?/rdbms/admin/catupgrd.sql,跑完再执行?/rdbms/admin/utlupp.sql和?/rdbms/admin/catuppst.sql。这条路能救回来,但前提是中断发生在字典升级阶段且没有产生部分提交的损坏,判断不了就别硬来,直接 flashback 回 restore point 重跑。

5. 升级避坑:五个真实翻车点的现象、原因与解法

升级这件事,成功的路径只有一条,失败的花样能列一页纸。下面这五个是我在实际演练和帮人排障时反复遇到的,每个都按「现象、原因、解决」写清楚,遇到对得上的直接照方抓药。

5.1 现象:19c 软件在目标机上装不上,报操作系统不支持

原因很直接,目标机是 Linux 6。19c 的安装程序在检查/etc/oracle-release或/etc/redhat-release时发现主版本号低于 7,直接终止安装,连选项都不给。有人尝试改oracle-release文件骗过检查,装是装上了,但后续链接二进制、跑 root 脚本都会出问题,属于自找麻烦。

解决办法只有一个:换一台 Linux 7 及以上的主机。这也正是整个方案要准备独立目标机的原因——生产环境的 11g 继续跑在老机器上,新机器装 19c,用 RMAN 把数据搬过去。搬过去之后源库不动,升级失败最多是演练环境重建,生产一点不受影响。如果实在没有新机器,虚拟化平台上开一台也比赛着改系统文件强。

5.2 现象:startup 报 ORA-00205,找不到控制文件

原因在参数文件改写这一步。从源库恢复出来的 spfile 里,control_files指向的是源库路径,可能是 ASM 的+DATA/...,也可能是另一台机器上的目录。目标机上这些路径不存在,实例启动时找不到控制文件,直接抛ORA-00205: error in identifying control file。

解决分两步。第一步,用 pfile 启动而不是 spfile,startup nomount pfile='/home/oracle/pfile.ora',绕开有问题的 spfile。第二步,把 pfile 里的control_files改成目标机上真实存在的路径,并且提前把目录建好:

mkdir -p /oradata/bsoftsb/controlfile/ chown -R oracle:oinstall /oradata/bsoftsb/

改完从 pfile 生成新的 spfile,再正常启动。这个坑的隐蔽之处在于,restore controlfile那一步是成功的,控制文件确实恢复了,报错发生在之后的实例重启,很容易误判成控制文件损坏。

5.3 现象:RMAN-06054 一直追不动,归档序列号断档

RMAN-06054前面提过,意思是缺某个 sequence 的归档。真正让人头疼的是补齐归档之后还是报同样的错,序列号一点没动。原因通常是归档传输中断过,中间缺了一个或多个 sequence,后面的归档即使拷过来也接不上,RMAN 不允许跳着追。

# 查最近一天备份的归档覆盖范围 rman target / list backup of archivelog from time 'sysdate-1'; # 输出里关注 Thrd、Seq、Low SCN、Next SCN 四列 # 如果 Seq 从 25190 跳到 25192,说明 25191 缺失

解决办法取决于缺的归档还能不能找到。源库如果还保留着,直接拷过来;源库已经删了,就看有没有增量备份可以应用,RECOVER DATABASE配合增量备份能把缺口补上。两样都没有,只能接受当前能追到的时间点,把这个时间点作为升级基线。所以我一般会在演练前就跟业务方确认好可接受的数据丢失窗口,别等追不动了才去扯皮。

5.4 现象:DBUA 停在高百分比长时间不动,被误判为卡死强杀

现象是进度条停在 93% 或者 96% 半小时没动,运维看着心慌,kill 掉进程重启,结果数据字典处于半升级状态,再也起不来。原因是 DBUA 的百分比是按步骤数估的,不是按时间,最后几个步骤是编译无效对象和跑收尾脚本,这两步在大库上耗时极长,而且日志输出稀疏,看起来就像死机。

正确的判断方式是看日志而不是看进度条。tail -f $ORACLE_BASE/cfgtoollogs/dbua/<dbname>/upgrade*/catupgrd*.log,只要还有新行输出,或者在编译某个包,就说明在干活。再辅助看一眼数据库会话:

-- 另开一个会话,看有没有活跃的升级会话 select sid, serial#, event, sql_id, status from v$session where program like '%dbua%' or module like '%DBUA%'; -- 看当前正在执行的 SQL select sql_text from v$sql where sql_id = '&sql_id';

只要能看到活跃会话和正在跑的 SQL,就耐心等。真要中断,也应该是从 DBUA 界面正常取消或者等它报错退出,不要kill -9。

5.5 现象:升级到一半报 ORA-01653,表空间无法扩展

现象是catupgrd日志里出现ORA-01653: unable to extend table SYS.XXX by 1024 in tablespace SYSTEM,升级中断。原因是 11g 的 SYSTEM、SYSAUX、UNDO 表空间按 11g 的字典规模规划,19c 的字典表更多更大,剩余空间不够。

解决要在升级前做,不是升级中做。preupgrade.jar 的报告里会给出建议的扩容量,照着加就行。手工检查的话跑这几条:

-- 检查 SYSTEM、SYSAUX、UNDO 的剩余空间与自动扩展设置 select tablespace_name, round(sum(bytes)/1024/1024/1024, 2) as total_gb, round(sum(maxbytes)/1024/1024/1024, 2) as max_gb from dba_data_files where tablespace_name in ('SYSTEM','SYSAUX','UNDOTBS1') group by tablespace_name; -- 检查临时表空间,升级期间排序操作很吃 TEMP select tablespace_name, round(sum(bytes)/1024/1024/1024, 2) as total_gb from dba_temp_files group by tablespace_name;

常见做法是把 SYSTEM 和 SYSAUX 的数据文件设成自动扩展,上限给到 30G 以上,UNDO 表空间至少留出 20G 余量。TEMP 表空间也别忘了,升级期间大量查询做排序,TEMP 不够会报ORA-01652。这些扩容操作在升级前做完,比升级中途救火省心得多。

6. 升级后验证与一个我每次都走的闭环

库升到 19c 能正常打开,只是走完了七成路。剩下三成是验证,验证不做,问题会延迟到业务上线后爆发,那时候排查成本翻几倍。我的验证顺序是四步:组件状态、无效对象、时区版本、性能基线。

组件状态查dba_registry,重点看 STATUS 列,OPTION 和 COMP_ID 是组件名,STATUS 必须是 VALID:

-- 确认所有组件状态为 VALID,版本号已变成 19.x select comp_id, comp_name, version, status from dba_registry order by comp_id; -- 确认补丁信息 select patch_id, action, status, action_time from dba_registry_sqlpatch order by action_time desc;

无效对象数量是升级质量的直接指标,正常升级完会有少量无效对象,DBUA 自动编译后应该收敛到个位数。如果超过几十上百个,说明有组件没升干净或者依赖缺失:

-- 统计无效对象,按 owner 分组看集中在哪个 schema select owner, count(*) as invalid_cnt from dba_objects where status = 'INVALID' group by owner order by invalid_cnt desc; -- 对业务 schema 逐个编译 begin dbms_utility.compile_schema(schema => 'BSPORTAL', compile_all => false); end; /

时区版本这个点容易被忽略。源库的时区文件版本如果比 19c 自带的老,涉及TIMESTAMP WITH TIME ZONE类型的查询可能算错,DBUA 里没勾升级时区的话,升级后要单独评估:

-- 查当前数据库时区版本 select * from v$timezone_file; -- 输出形如:VERSION 32, FILENAME timezlrg_32.dat

性能基线是最容易被跳过、又最能救命的一步。升级前在源库采一份 AWR 快照,升级后在 19c 上采一份,对比 TOP 等待事件和 TOP SQL 的执行计划。19c 的优化器比 11g 激进,有些在 11g 上走索引的 SQL 到了 19c 可能改走全表扫描,这种事不看基线根本发现不了。具体做法是升级前exec dbms_workload_repository.create_snapshot(),升级后同样执行一次,然后awrrpt.sql生成两份报告对比。

最后说一个我每次都强制走完的闭环动作:把preupgrade_fixups.sql和postupgrade_fixups.sql这两个脚本的执行结果落盘归档,连同 DBUA 的upgrade_summary.log一起存到一个以日期命名的目录里。这些文件记录的是这次升级在数据字典层面到底改了什么,半年后业务方报一个问题,说某个功能在升级后行为变了,翻出这份归档,比重新查 MOS 快得多。第一次做升级的时候我嫌麻烦没留,后面为了定位一个字符集相关的诡异问题,花了两天从归档日志里一点点反推,从那以后每次升级完,我都会先把这三个文件拷进归档目录、确认可读,再去做别的收尾。希望帮到你。

本文还有配套的精品资源,点击获取