简介:这份 Oracle 数据库补丁包面向运行 11.2.0.4 版本的 64 位 Linux 环境 DBA、运维人员和数据库实验者,对应 2022 年 1 月发布的 PSU 更新,补丁标识为 p33477185,核心用途是获取安全修复、性能增强以及对已知问题的解决方案。压缩包共 3658 个文件,整体约 436.52MB,包含大量 so 动态库、o 对象文件、xml 元数据、sql 脚本,以及 jar、class、plb 等组件,并附带 PatchSearch.xml 等补丁说明性文件,方便核对补丁内容、适用条件和文件组成。其中动态库与对象文件构成包体主要部分,XML、SQL 等文件则记录补丁元数据及数据库对象变更信息,目录中还可见 libfreetype、libnnzst11.a 等库文件,较完整地保留了该 PSU 的介质结构。已有 861 人学习下载,适合需要留存 Oracle 11.2.0.4 补丁介质、检查文件完整性、做版本比对或在隔离测试环境中验证兼容性的读者参考。
1. 手上还剩一套 11.2.0.4:p33477185 这个 2022 年 1 月的 DB PSU 值不值得动
季度基线一拉,机房里那套 Oracle 11.2.0.4 的补丁水位还停在几年前,扫描报告里一串组件版本命中,业务方又明确说不能做大版本升级。翻补丁目录,能落地的最后一班车基本就是这个 p33477185——DB-PSU-11.2.0.4.220118,Linux x86-64 平台。它是 11gR2 末期的一条数据库补丁集更新,只针对 Database Home,不动 GI,也不含 OJVM 那部分。适合的人群很明确:还在维护 11gR2 单实例或 RAC 的 DBA、要给老系统续命又不敢碰大版本的人、以及被基线检查追着跑但手里只有这套库的人。后面按我实际落地的顺序拆:先分清补丁身份,再核 OPatch 与环境,然后两段式执行,最后对账与回滚。
2. 先分清补丁身份:DB PSU、GI PSU、OJVM 与 OPatch 版本对齐
补丁包下错、打错位置,是这类老版本运维里返工率最高的环节。11.2.0.4 到了后期,官方把补丁拆得比较细,同一个季度的补丁会以不同形态出现:只覆盖 Database Home 的 DB PSU、覆盖 Grid Infrastructure 的 GI PSU、以及单独发布的 OJVM PSU。标题里这个 p33477185 明确写了 DB-PSU,说明它是数据库侧的补丁集更新,落到$ORACLE_HOME而不是 GI Home。这个判断必须先做对,否则后面所有命令都是在错误的目录里执行。
2.1 用 inventory 和集群状态确认 Home 类型
在动手之前,先花两分钟确认这台机器上到底有几个 Oracle Home、当前登录的ORACLE_HOME是 DB 还是 GI。看不见的东西最容易被误操作,尤其是同一台机器上 DB Home 和 GI Home 并存的时候,环境变量一export错,补丁就打到了不该打的地方。
# 1. 看当前会话指向哪个 Home echo $ORACLE_HOME echo $ORACLE_SID # 2. 看 Home 类型,DB Home 一般形如 OraDB11204_home grep -i "HOME_TYPE" $ORACLE_HOME/inventory/ContentsXML/inventory.xml # 3. 判断是不是 RAC/GI 环境 $ORACLE_HOME/bin/crsctl query crs activeversion 2>/dev/null || echo "非 GI 环境或未配置"第一段确认环境变量,防止在错误的 shell 里执行;第二段的HOME_TYPE是 inventory 里的 Home 标识,常见取值形如OraDB11204_home、OraGI11204_home,不同安装方式会有差异,以实际输出为准;第三段用crsctl探测 GI 是否在跑,返回版本号说明这台机器有集群栈,返回报错基本可以按单实例处理。三条命令跑完,心里就该有数:这次要打的是 DB Home,还是连 GI Home 一起动。
如果是 RAC,还要额外确认一件事:ORACLE_HOME是不是共享的。共享 Home 的补丁流程和单机不一样,后面第 4 章会展开。判断方法看$ORACLE_HOME是否挂在共享存储上,或者直接看/etc/oratab与集群资源的关系。
2.2 DB PSU 与 GI PSU 的边界,以 README 为准
很多老 DBA 凭记忆记补丁包含关系,结果在 RAC 上打了 DB PSU 却漏了 GI 侧,或者反过来重复打。稳妥的做法是打开补丁包里的README.html,重点看两处:一是Patch Installation章节列出的前置条件和适用 Home,二是Bugs Fixed或者被包含补丁清单,确认这条补丁是否已经覆盖了你想打的其他补丁。
我一般会这样快速检索 README 的关键段落:
cd /u01/soft/psu/33477185 # 看补丁适用平台和 Home 类型 grep -i -A3 "platform" README.html | head -40 # 看安装前置要求,尤其是 OPatch 最低版本 grep -i -B2 -A6 "OPatch" README.html | head -60第一条grep用来确认补丁包确实覆盖 Linux x86-64,避免拿到别的平台包;第二条专门捞 OPatch 的最低版本要求,这是后面最容易翻车的点。README 里通常会写明“需要 OPatch 版本不低于某个值”,这个值必须照做,凭经验拍脑袋升级到某个版本,很可能在opatch apply的最后一步报版本不兼容。
需要强调一点:不要假设 GI PSU 一定包含 DB PSU 的全部内容,也不要假设打了 DB PSU 就等于 GI 侧也安全了。以 README 里明确写的包含关系为准,拿不准就把两个包的Bugs Fixed清单拉出来比对补丁号。
2.3 OPatch 版本:先看版本,再谈 apply
OPatch 是补丁的入口,版本低了会在apply阶段直接拒绝执行,这个报错信息还算友好,至少不会打一半。真正麻烦的是版本介于“能跑”和“该升级”之间,检查能过,apply 到最后 relink 失败,回退又得走一遍流程。
先看当前版本:
export ORACLE_HOME=/u01/app/oracle/product/11.2.0/dbhome_1 export PATH=$ORACLE_HOME/OPatch:$ORACLE_HOME/bin:$PATH opatch version opatch lsinventory -detail | head -40 opatch lspatchesopatch version输出当前 OPatch 版本,和 README 要求的最低版本直接对比;lsinventory -detail打印当前 Home 里已安装的补丁和组件信息,是打补丁前的“基线快照”,建议把输出重定向存一份;lspatches是更紧凑的已装补丁列表,打完之后还要再跑一次做前后对比。
11.2.0.4 后期的补丁对 OPatch 版本要求比较靠后,常见的做法是:先去补丁包 README 里确认最低版本,如果当前版本低于要求,就从官方补丁渠道取对应 11.2.0.4 的 OPatch 包(补丁号 6880880 系列)做替换升级,具体版本以 README 为准,不要跨大版本乱换。第 3 章会给出替换步骤和注意事项。
2.4 打补丁前的环境核查清单
补丁本身不复杂,复杂的是环境。下面这张表是我每次动手前都会过一遍的核查项,缺一项就往下走,大概率在后面某个环节卡住。
| 核查项 | 检查命令/方式 | 通过标准 |
|---|---|---|
| 磁盘空间 | df -h $ORACLE_HOME | 剩余空间至少能容纳一份 Home 备份和补丁解压 |
| 实例状态 | ps -ef | grep pmon | 明确知道哪些实例在跑,何时能停 |
| 归档模式与备份 | archive log list | 数据库有可用备份,或至少做了冷备 |
| OPatch 版本 | opatch version | 不低于 README 要求 |
| 已装补丁 | opatch lspatches | 输出已存档,作为回滚对照 |
| 补丁包完整性 | unzip -l、比对校验值 | 解压无报错,文件数与官方清单一致 |
| 监听与服务 | lsnrctl status | 知道补丁窗口内哪些连接会断 |
表格里最容易被跳过的是“补丁包完整性”。下载中断导致的半包,解压时不报错,opatch apply到一半才发现文件缺失,那时候 Home 已经被改了一部分,处理起来很难受。解压后先ls一遍目录结构,应该有etc/、files/以及按组件分的子目录,数量对得上再继续。
3. 动手前的三道闸:OPatch 升级、冲突检查、可回退备份
把这一章单独拎出来,是因为它决定了出问题时你还有没有后悔药。补丁打失败的代价,从来不是补丁本身,而是“没法干净地退回去”。三道闸按顺序过:先保证工具链够新,再确认补丁和目标 Home 不冲突,最后把可回退的现场固化下来。
3.1 升级 OPatch:改名、解压、验权
OPatch 的替换本质上就是换目录,但直接覆盖会丢旧版本,出问题没法对比。我的习惯是把旧目录改名保留,新包解压到原位,权限对齐。
# 1. 先记录旧版本 opatch version > /tmp/opatch_version_before.txt # 2. 备份旧 OPatch 目录(改名而不是删除) cd $ORACLE_HOME mv OPatch OPatch.bak.$(date +%Y%m%d) # 3. 解压新 OPatch 包到 $ORACLE_HOME unzip -q /u01/soft/p6880880_112000_Linux-x86-64.zip -d $ORACLE_HOME # 4. 校验属主与权限,必须与 oracle 用户一致 chown -R oracle:oinstall $ORACLE_HOME/OPatch chmod -R 775 $ORACLE_HOME/OPatch # 5. 验证 $ORACLE_HOME/OPatch/opatch version第一步留版本记录,升级出问题能立刻知道原来是什么版本;第二步改名而不是删,是最省事的回退路径;第三步解压时注意压缩包内层通常已经带OPatch目录,-d指向$ORACLE_HOME即可,解压完检查是不是变成了OPatch/OPatch,如果是就说明路径多套了一层,需要手动调整;第四步的属主权限经常被忽略,用 root 解压后忘了chown,opatch会以奇怪的方式报权限错误;第五步必须跑,确认新版本生效且路径正确。
提示:升级 OPatch 期间不要有其他会话在调用
$ORACLE_HOME/OPatch下的脚本,改名的瞬间如果有并发的补丁检查任务在跑,会拿到“文件不存在”的报错。
3.2 冲突检查:把问题挡在 apply 之前
opatch apply自身会做冲突检查,但等到那一步才发现冲突,时间窗口已经被占用了。提前单独跑一次检查,成本几秒钟,收益是把问题提前暴露。
cd /u01/soft/psu/33477185 # 检查补丁与当前 ORACLE_HOME 的冲突,输出明细 $ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./ # 检查补丁前置条件(组件版本、Home 类型等) $ORACLE_HOME/OPatch/opatch prereq CheckSystemSpace -ph ./第一条命令做的是补丁与已安装组件的冲突比对,-ph ./指定补丁所在目录,输出里如果有Conflict字样,必须逐条看清楚是哪个组件、哪个补丁号冲突;第二条检查系统空间,虽然只是粗略判断,但能提前发现磁盘不够这种低级问题。
冲突检查不通过时,处理方式取决于冲突类型:如果是同一组件的不同补丁版本冲突,通常需要先确认已装补丁是否已被新补丁包含;如果是文件级冲突,说明 Home 被非标准手段改过(比如手工替换过某个.so),这种情况要先查清楚是谁改的,不要硬上。
3.3 可回退备份:Home 冷备加数据库备份
补丁回滚有两条路:opatch rollback走官方回退,或者整目录还原走冷备。前者快,但依赖 inventory 完整;后者慢,但兜底能力强。两手都准备,才叫有后悔药。
# 1. 停库(单实例) sqlplus / as sysdba <<'EOF' shutdown immediate exit EOF # 2. 停监听,避免补丁期间有新连接 lsnrctl stop # 3. 冷备 ORACLE_HOME(排除日志和临时目录,减少体积) tar -czf /u01/backup/oracle_home_before_psu_$(date +%Y%m%d).tar.gz \ --exclude='$ORACLE_HOME/log' \ --exclude='$ORACLE_HOME/rdbms/log' \ -C $ORACLE_HOME . # 4. 备份 inventory 和关键配置 cp -a $ORACLE_HOME/inventory /u01/backup/inventory_bak_$(date +%Y%m%d) cp -a /etc/oratab /u01/backup/oratab_bak_$(date +%Y%m%d)第一步停库是必须的,DB PSU 会替换二进制并重新链接,实例在跑的情况下opatch apply会直接拒绝;第二步停监听是为了避免补丁窗口内出现半连接状态;第三步的tar里-C $ORACLE_HOME .表示从 Home 根目录打包,注意排除项按实际路径调整,不要把dbs/目录整个排掉,那里有 spfile 和密码文件;第四步单独备份 inventory 和oratab,是因为回滚时 inventory 的完整性直接决定opatch rollback能不能跑通。
RAC 环境下停库用srvctl stop database -d <dbname>,确认所有实例都停了再动手。数据库侧的逻辑备份(RMAN 或导出)同样建议做一份,虽然补丁不改数据文件,但catbundle.sql会动数据字典,留一份备份心里踏实。
4. 正式落地:opatch apply 与 catbundle.sql 的两段式执行
11.2.0.4 打 PSU 是两段式的:第一段用 OPatch 把二进制补丁落到 Home 并重新链接,第二段用catbundle.sql把数据字典部分刷进去。两段都完成,才算补丁真正生效。只做第一段是这类操作里最隐蔽的错误——opatch lspatches显示成功,数据库也能起来,但数据字典里的版本号没动,视图和包的逻辑还是旧的。
4.1 第一段:opatch apply 的正确姿势
# 1. 确认环境变量正确,且实例已停 echo $ORACLE_HOME ps -ef | grep pmon | grep -v grep # 2. 进入补丁目录执行 cd /u01/soft/psu/33477185 $ORACLE_HOME/OPatch/opatch apply # 3. 静默执行(适合脚本化,交互确认会被跳过) # $ORACLE_HOME/OPatch/opatch apply -silent # 4. 检查结果与日志 $ORACLE_HOME/OPatch/opatch lspatches ls -lt $ORACLE_HOME/cfgtoollogs/opatch/ | head第一步再确认一遍环境,防止中途切换过 shell;第二步的apply会先做一轮检查,然后列出要修改的文件,交互确认时输入y;第三步的-silent适合批量节点执行,但第一次打这个补丁时不建议用,交互输出里经常藏着关键警告;第四步的lspatches必须能看到补丁号,日志目录下会生成带时间戳的opatch_*.log,出错时第一时间看这个日志的最后 50 行,比看屏幕回滚信息有用。
共享ORACLE_HOME的 RAC 环境要注意:补丁在节点 1 执行完成后,其余节点需要补做本地链接与 inventory 记录,常见做法是在各节点用opatch apply -local再跑一次,具体以 README 的 RAC 安装章节为准。只在一个节点执行,其他节点的二进制文件虽然是共享的,但本地链接和 inventory 状态可能不一致,后面起实例会报奇怪错误。
apply成功后的输出里会有一行提示,让你去执行数据字典部分的脚本,这个提示不要跳过,那就是第二段的入口。
4.2 第二段:catbundle.sql 刷数据字典
11.2.0.4 上没有datapatch(那是 12c 之后的工具),数据字典部分靠catbundle.sql完成。这一步要在数据库启动到 open 状态后执行。
# 1. 启动实例(单实例) sqlplus / as sysdba <<'EOF' startup exit EOF # 2. 执行 catbundle,参数是 psu apply cd $ORACLE_HOME/rdbms/admin sqlplus / as sysdba <<'EOF' @catbundle.sql psu apply exit EOF # 3. 查询注册历史,确认记录已写入 sqlplus / as sysdba <<'EOF' set lines 200 pages 100 col action format a12 col namespace format a12 col comments format a40 select action_time, action, namespace, version, id, comments from dba_registry_history order by action_time desc; exit EOF第一步startup时注意观察告警日志,补丁后第一次启动偶尔会有组件加载警告,多数能在后续编译中消掉,但要在日志里留个记录;第二步的catbundle.sql参数含义是补丁类型加动作,psu apply表示应用 PSU 的数据字典变更,如果要回退数据字典部分则是psu rollback(是否支持取决于补丁,执行前先确认);第三步查dba_registry_history,最新一条的action应该是APPLY,namespace对应PSU,comments里通常带补丁号。
catbundle.sql的执行日志一般落在$ORACLE_HOME/cfgtoollogs/catbundle/下,文件名带APPLY和时间戳。脚本执行过程中如果有 ORA- 报错,不要只看屏幕,去这个日志里搜ERROR,很多报错在屏幕上被刷过去了。
注意:
catbundle.sql会重编译大量数据库对象,执行时间在几分钟到十几分钟不等,视数据库对象数量而定。这期间不要中断会话,中断后数据字典可能处于部分更新状态,需要用同样的命令重跑一次。
4.3 RAC 与多实例的顺序控制
RAC 环境的顺序比单机严格,错一步就要多花半小时排查。
# 1. 停整个数据库(所有实例) srvctl stop database -d ORCL # 2. 各节点执行 opatch(共享 Home 用 -local) # 节点1 cd /u01/soft/psu/33477185 && $ORACLE_HOME/OPatch/opatch apply # 其余节点 cd /u01/soft/psu/33477185 && $ORACLE_HOME/OPatch/opatch apply -local # 3. 起库 srvctl start database -d ORCL # 4. 在任一实例执行 catbundle,数据字典共享,只需一次 sqlplus / as sysdba SQL> @?/rdbms/admin/catbundle.sql psu apply第一步停整库而不是逐个停实例,避免补丁过程中有实例被自动拉起;第二步分节点执行,-local的作用是只处理本节点的链接与 inventory;第三步起库后确认所有实例都到 open;第四步的catbundle.sql因为数据字典是共享的,只需要在一个实例执行一次,执行完在任意实例查dba_registry_history都能看到记录。
还有一个容易漏的点:GI Home 如果也需要打补丁,顺序一般是先 GI 后 DB。GI 侧的操作涉及集群栈,通常用opatch auto或者按 README 的手工流程停集群,风险比 DB 侧高,时间窗口要留足。这次标题里是 DB PSU,如果 GI 侧有独立补丁需求,注意不要混在同一次窗口里做。
4.4 apply 之后必须验的三处
补丁打没打上,不能只看一条命令。三处交叉验证,任何一处对不上都要查清楚。
| 验证点 | 命令 | 期望结果 |
|---|---|---|
| 二进制补丁 | opatch lspatches | 列出 33477185 或对应补丁号 |
| 数据字典 | select * from dba_registry_history | 最新记录 action 为 APPLY |
| 组件版本 | select comp_name, version, status from dba_registry | 相关组件状态 VALID |
第一处是 OPatch 层面,第二处是数据字典层面,第三处是组件健康度。三处都过,说明补丁落地完整。如果第一处过、第二处没过,就是catbundle.sql漏跑或者失败;如果前两处都过、第三处有 INVALID,通常是重编译没做完,跑一次utlrp.sql再查。
5. 五个翻车现场:从 OPatch 版本不匹配到 catbundle 漏跑
补丁流程本身不复杂,翻车基本都集中在几个固定位置。下面五条按我遇到过的频率排序,每条按“现象、原因、解决”写,对照着排查能省不少时间。
5.1 现象:opatch apply 报 OPatch 版本不满足要求
原因:README 里写明的最低 OPatch 版本没有满足,当前 OPatch 版本偏旧,检查阶段直接被拒。
解决:按第 3.1 节的步骤替换 OPatch,替换前记录旧版本,替换后opatch version确认。替换完重新跑opatch prereq CheckConflictAgainstOHWithDetail -ph ./,确认检查通过再 apply。不要试图改补丁包里的版本声明绕过,那样 apply 到 relink 阶段失败的概率很高。
5.2 现象:apply 到一半报 relink 失败,Home 处于半更新状态
原因:常见于 Home 被非标准手段改过,或者系统缺少必要的编译工具链(gcc、make 版本不匹配)。11.2.0.4 的 relink 对编译器和系统库版本有要求,系统升级过之后容易踩。
解决:先看$ORACLE_HOME/cfgtoollogs/opatch/下最新日志里 relink 的具体报错,如果是编译器问题,装齐对应版本的开发工具;如果是文件冲突,用第 3.3 节的冷备还原整个 Home,再排查冲突来源。半更新状态不要强行opatch rollback,inventory 可能已经不一致,冷备还原更干净。
5.3 现象:opatch 成功、数据库能起,但 dba_registry_history 没有新记录
原因:只做了第一段,catbundle.sql没跑或者跑了但中途报错回退。
解决:确认实例处于 open 状态,重新执行@?/rdbms/admin/catbundle.sql psu apply,执行完再查dba_registry_history。如果重跑时报“已应用”类错误,去看$ORACLE_HOME/cfgtoollogs/catbundle/下的日志,确认上一次是不是部分完成,必要时按日志提示处理后再跑。
5.4 现象:RAC 环境一个节点正常,另一个节点起实例报错
原因:共享 Home 场景下,其他节点没有用-local补做本地链接与 inventory 记录,本地状态和共享文件不一致。
解决:在报错节点上确认 inventory 状态,按 README 的 RAC 流程用opatch apply -local补做,然后重新起实例。补做之前先停该节点实例,避免链接过程中有进程占用文件。
5.5 现象:补丁后部分视图、包报 ORA-04063 或执行变慢
原因:catbundle.sql完成后没有重编译无效对象,数据字典更新让一部分依赖对象失效,首次调用时才触发编译,表现为偶发报错或首次执行慢。
解决:跑一遍@?/rdbms/admin/utlrp.sql,跑完查无效对象数量:
select count(*) from dba_objects where status = 'INVALID';正常情况下这个数应该接近 0,如果有残留,查dba_objects里具体是哪些对象,多数是业务自定义对象,和补丁无关,但要在窗口内一并处理掉。
6. 回滚与对账:三条命令确认补丁真落进了数据字典
补丁打完之后,我最不愿意看到的场景是:一周后业务报某个功能异常,翻记录发现当时的补丁验证只跑了opatch lspatches一条命令。所以收尾这一步必须做扎实。
先说回滚。opatch rollback是官方路径,前提是 inventory 完整、Home 没被非标准改过:
# 停库后执行回滚 sqlplus / as sysdba <<'EOF' shutdown immediate exit EOF cd /u01/soft/psu/33477185 $ORACLE_HOME/OPatch/opatch rollback -id 33477185 # 起库后回退数据字典部分(是否支持以补丁 README 为准) cd $ORACLE_HOME/rdbms/admin sqlplus / as sysdba <<'EOF' @catbundle.sql psu rollback exit EOF-id后面跟完整补丁号,回滚前必须停实例。数据字典部分的回退要谨慎,不是所有补丁都完整支持psu rollback,执行前先看 README 的 Deinstallation 章节。如果 README 没写支持,就不要单独回退数据字典,直接走冷备还原整机更稳。
再说对账。三条命令,缺一不可:
| 顺序 | 命令 | 看什么 |
|---|---|---|
| 1 | opatch lspatches | 补丁号是否在列表,前后对比有无意外增减 |
| 2 | select * from dba_registry_history order by action_time desc | 最新一条 APPLY 记录的时间、补丁号是否对得上 |
| 3 | select comp_name, version, status from dba_registry | 组件状态是否 VALID,版本串是否变化 |
第一条对比的是打补丁前存的那份lsinventory输出,重点不是“有没有新补丁”,而是“有没有少东西”。第二条看时间戳和补丁号,确认catbundle.sql那一段确实写进去了。第三条看组件健康度,INVALID状态要先处理再交付。
一个具体的技巧:打完补丁后立刻跑一次utlrp.sql,然后再查无效对象数量,把结果记进变更单。这个数字是后面出问题时的基线——如果一周后无效对象突然变多,至少能证明不是补丁遗留的,排查方向直接转向业务侧的 DDL 变更。
血泪经验是:不要相信“补丁打完了,数据库能连上”这种结论。补丁的验证标准应该是三处对账全部通过,再加上一次业务关键路径的冒烟测试。从那以后我每次打补丁,无论多小的窗口,都会把lspatches、dba_registry_history、dba_registry这三条命令的输出存成一份文本,和变更单一起归档,谁问起来直接翻记录,不用靠回忆。
希望帮到你。
本文还有配套的精品资源,点击获取