Oracle 11g补丁安装全流程:从包识别到SQL注册验证
简介:面向Oracle数据库DBA与运维人员的11.2.0.3.15补丁集更新包,对应补丁号20760997,适用于Linux x86-64平台,并集成2015年7月CPU安全更新,主要用于修复已知安全漏洞、性能与稳定性问题,适合版本升级、安全加固或补丁应用前的资料核对。压缩包为zip格式,体积约100.73MB;文件总数显示为0、类型明细暂未提供,描述中可见PatchSearch.xml补丁搜索配置与20760997补丁程序等内容,实际以解压结果为准。已有291人浏览学习,说明该补丁在旧版本环境维护中仍有一定参考需求。对仍运行11.2.0.3的旧系统,该包可作为补丁归档、安全审计与升级前评估的参考材料;读者可据此了解补丁的适用版本、平台范围与CPU包含关系,并借助包内说明核对适用性、依赖关系与安装注意事项,为数据库安全加固和日常维护提供依据。
1. 补丁包先看清:p20760997_112030_Linux-x86-64 对应哪个库版本
上周有人丢给我一个包,名字叫p20760997_112030_Linux-x86-64.zip,说 oracle patch 打完了,但库起不来。我打开一看,opatch lspatches里确实有记录,可startup之后报了一串组件失效。问题不在补丁本身,在于打之前没人把文件名读明白:112030不是批次号也不是平台码,它是 11.2.0.3.0 压成六位的版本段,Linux-x86-64才是平台。版本段对不上你手上的 Oracle Home,opatch 可能照样返回成功,但 SQL 注册那一步会悄悄跳过,最后留下一个“看着装好了、实际半残”的库。这套流程适合还在维护 11g 老库、需要按季度跟补丁的运维和 DBA,新手照着能走通,熟手可以对照检查自己漏了哪一步。
2. 装前环境核对:内核、属主与 OPatch 版本三件事
补丁装挂的人,十个里有八个不是倒在opatch apply,而是倒在 apply 之前没核对。补丁包本身只是几个二进制和一堆 SQL,它能不能落地,取决于你的 Oracle Home 是不是它认识的那个 Home、OPatch 够不够新、文件系统还剩多少。这一章的三件事必须在解压之前做完,做完之后你对“这个包能不能打”会有一个明确结论,而不是打到一半靠猜。
2.1 先确认这个 zip 是给哪个 Oracle Home 的
第一步永远是以 oracle 用户登录,而不是 root。Oracle 的补丁工具大量依赖$ORACLE_HOME和$ORACLE_SID,用 root 跑出来的结果要么权限错乱,要么读到另一个 Home。登录后先把环境变量和平台确认一遍,再进库看版本,两条路互相印证。
# 必须是 oracle 用户,且环境变量来自 oraenv 或 .bash_profile id echo "ORACLE_HOME=$ORACLE_HOME" echo "ORACLE_SID=$ORACLE_SID" uname -m # 期望输出 x86_64 uname -r # 记下内核版本,部分老版本对内核有最低要求uname -m回x86_64才说明平台对得上;如果回i686,那是 32 位内核,这个包直接用不了。$ORACLE_HOME的路径也要留意,同一台机器上装了 11.2.0.3 和 12.1.0.2 两套 Home 是常事,环境变量指错一次,补丁就打到另一个库上去了。
-- 以 sysdba 登录后执行,确认库的版本与补丁文件名里的版本段一致 select banner from v$version; -- 如果是 RAC,还要看这一行,决定后面用不用 -local 逐节点打 select * from v$option where parameter = 'Real Application Clusters';v$version第一行通常形如Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production,这里的11.2.0.3.0就是文件名里112030展开的样子。对不上就别往下走了,先去确认这个补丁包是不是拿错了。RAC 那一条如果返回TRUE,说明后面每一步都要考虑节点:opatch apply默认会尝试处理所有节点,网络不通或对方节点没停库时会卡住,稳妥做法是加-local一个节点一个节点来。
2.2 OPatch 版本对不上,后面全白搭
OPatch 是补丁的搬运工,它自己也有版本。补丁包解压后目录里有个README.txt或README.html,开头几行会写OPatch version required,一般要求不低于 11.2.0.3 分支的某个小版本。实操里我一般不抠那个最低值,直接换到该分支能拿到的最新 OPatch,省得在 prereq 阶段被拦一次。
# 查当前 OPatch 版本,输出形如 OPatch Version: 11.2.0.3.x $ORACLE_HOME/OPatch/opatch version # 换 OPatch 的标准动作:先备份,再解压新版本,最后修属主 cd $ORACLE_HOME mv OPatch OPatch.bak.$(date +%Y%m%d) unzip -q /u01/stage/p6880880_112000_Linux-x86-64.zip -d $ORACLE_HOME chown -R oracle:oinstall $ORACLE_HOME/OPatch chmod -R 750 $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch/opatch version # 再确认一次mv而不是直接覆盖,是为了留一条退回的路:新 OPatch 万一和更早的补丁不兼容,把OPatch.bak.*改回来就行。解压用-d $ORACLE_HOME是因为压缩包里自带OPatch这一层目录,解到 Home 下正好落位。chown和chmod两步不能省,root 解压出来的文件属主是 root,opatch 运行时写日志会直接报权限拒绝。
注意:12c 以后的 OPatch 不能拿去给 11g 的 Home 用,反过来也一样,跨大版本替换是另一个高频翻车点。
2.3 空间、属主和一份能救命的备份
补丁应用时会在$ORACLE_HOME/.patch_storage下留一份原始文件副本用于回滚,所以空间需求不是补丁包大小,而是它的三到五倍。我见过补丁包 300MB、应用时把 4GB 的 Home 撑爆的情况,报错是No space left on device,而且往往发生在 apply 中途,比一开始就失败更麻烦。
# 看 Home 所在文件系统和 /tmp 的余量,建议 Home 至少留 3GB df -h $ORACLE_HOME df -h /tmp du -sh $ORACLE_HOME/.patch_storage 2>/dev/null # 补丁前的库存快照,出问题就靠它比对 $ORACLE_HOME/OPatch/opatch lsinventory -detail \ > /u01/stage/lsinventory_before_$(date +%Y%m%d).log-detail会把已打的补丁号、组件版本、Home 路径全列出来,这份日志的价值在于事后比对:装完之后哪些补丁号多了、哪些组件版本变了,一眼能看出来。
备份这件事我吃过亏,所以现在是硬性动作:库停在 mount 或直接shutdown immediate之后,用 RMAN 做一次全备加归档备份,或者至少把$ORACLE_HOME打包一份放别的盘。原因是opatch rollback只回退二进制,不回退catbundle.sql或datapatch做过的数据字典变更,SQL 那一层想退只能靠备份恢复。备份这一步花二十分钟,能省掉后面一整天。
3. 解包与冲突检查:apply 之前把黑匣子打开
补丁包解压出来不是一个文件,而是一个带编号的目录,里面etc/config存着补丁元数据,files下是按 Oracle Home 相对路径摆好的二进制和 SQL。这个结构决定了你不能随便换个地方解压,也不能用 root 解压完就直接打。这一章要做的事,是把“这个补丁会改哪些文件、和现有补丁冲不冲突”提前问清楚,而不是等 opatch 报错再回头查。
3.1 上传、解压与属主修正
暂存目录我习惯放在$ORACLE_BASE之外的独立挂载点,比如/u01/stage,避免补丁包把数据盘撑满。上传方式看环境,能直连就scp,中间隔着跳板机就用sftp分段传,传完先核对大小和校验和,再解压。
# 建独立暂存目录,避免和已有的补丁混淆 mkdir -p /u01/stage/p20760997 cd /u01/stage # 传完先校验,md5 与提供方给出的一致再往下走 md5sum p20760997_112030_Linux-x86-64.zip # 解压到独立目录,-q 静默、-d 指定落点 unzip -q p20760997_112030_Linux-x86-64.zip -d /u01/stage/p20760997 # 用 root 上传的话,属主和权限要改回来 chown -R oracle:oinstall /u01/stage/p20760997 chmod -R 750 /u01/stage/p20760997 ls -l /u01/stage/p20760997unzip -d指定落点的好处是解压结果干净,不会和暂存目录里其他补丁的编号目录混在一起。chmod 750是 Oracle 一贯的目录权限习惯,组内可读可执行、其他用户无权限,补丁目录沿用这个设置不会和 Home 的权限模型打架。解压后进到编号目录里扫一眼,确认有etc、files、README.txt三样东西,缺任何一样说明包不完整,重新下载。
cd /u01/stage/p20760997/20760997 ls -l cat README.txt | head -60 # 重点看 OPatch 要求和前置补丁说明README 里除了 OPatch 版本,还会写“需要先打哪些前置补丁”。这一句经常被跳过,结果就是 apply 时报一串冲突,然后再回来翻文档。
3.2 lsinventory 与 prereq 的两条基线
opatch 提供了两组只读命令,一组看现状,一组看可行性。现状用lsinventory,可行性用prereq,两组都跑完,你对这次操作的成功率心里就有数了。
cd $ORACLE_HOME/OPatch # 现状:已装补丁清单,重点是最后那几行 patch 编号 ./opatch lsinventory # 可行性一:检查补丁与当前 Home 的冲突 ./opatch prereq CheckConflictAgainstOHWithDetail -ph /u01/stage/p20760997/20760997 # 可行性二:检查目标文件系统是否有足够空间 ./opatch prereq CheckSystemSpace -ph /u01/stage/p20760997/20760997 # 可行性三:检查 Home 内是否有活动进程占用将被替换的文件 ./opatch prereq CheckActiveFilesAndExecutables -ph /u01/stage/p20760997/20760997-ph后面跟的是补丁编号目录的绝对路径,不是 zip 文件。这三条prereq都是只读的,跑多少次都不会改动 Home,可以放心在业务库上执行。CheckActiveFilesAndExecutables这一条尤其值得单独跑:库没停干净、监听还在、或者某个客户端进程占着libclntsh.so,它都会直接指出来,省掉 apply 到一半失败再回滚。
输出里出现Prerequisite check "xxx" passed才算通过;出现failed时后面会跟具体原因,通常是“文件被占用”或“补丁冲突”,按第 5 章的排查思路处理。
3.3 冲突检测与回滚预案
冲突分两种:一种是补丁与已装补丁的二进制冲突,另一种是同一个 Home 上已经存在更新版本的同类补丁。前者 opatch 会在CheckConflictAgainstOHWithDetail里报出来,后者需要你自己看lsinventory的补丁列表判断——比如季度补丁是累积的,打了 7 月的再回头打 4 月,opatch 可能允许,但把新版本降回旧版本,属于自找麻烦。
# 冲突检测的更细粒度版本,会列出具体冲突文件 cd /u01/stage/p20760997/20760997 $ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./ # 万一要回退,先记住这个命令的形状,补丁号来自文件名的 p 后面那串 # $ORACLE_HOME/OPatch/opatch rollback -id 20760997-ph ./这种写法在已经cd进编号目录的前提下更省事,.就代表当前目录。回滚命令我只建议在“补丁打完了才发现不兼容”时用,而且前提是$ORACLE_HOME/.patch_storage里那份原始副本还在——有些人清空间时顺手把这个目录删了,等于把回滚能力一起删了。
真正完整的回滚预案是三层的:第一层opatch rollback -id回退二进制;第二层从 RMAN 备份恢复数据文件,把 SQL 变更一并退掉;第三层是应用侧的回退方案,比如应用连接串或驱动版本要不要跟着调。三层里最容易被忽略的是第二层,因为大家默认“补丁装坏了回滚一下就行”,而实际上 SQL 注册那一步做完之后,单靠 opatch 是退不干净的。
注意:
.patch_storage目录不要手工清理,里面的备份文件是 opatch 回滚的唯一依据。
4. 应用补丁:opatch apply 与 SQL 注册两步走
前面的检查全绿,才轮到真正动手。这个过程分两段,中间隔着一次启库:第一段停库、跑opatch apply改二进制,第二段启库、跑 SQL 脚本改数据字典。很多人只做了第一段就以为完事,第二段漏掉,表现就是库能起来、补丁也显示装了,但查询性能问题和已知 bug 一个没修——因为修复 SQL 根本没进字典。
4.1 停库停监听的正确顺序
停的顺序是先库后监听,起的时候反过来。这个顺序不是仪式感,是因为监听先停会让应用侧连接报错刷屏,而库先停能让会话干净退出,减少CheckActiveFilesAndExecutables失败的概率。
export ORACLE_SID=orcl # 第一步:干净关闭实例,immediate 让会话回滚退出,不要用 abort sqlplus -s / as sysdba <<'EOF' shutdown immediate; exit EOF # 第二步:停监听 lsnrctl stop # 第三步:确认没有残留进程占着 Home ps -ef | grep -E "ora_pmon|tnslsnr" | grep -v grepshutdown immediate会回滚未提交事务并做检查点,正常库几十秒内完成;如果卡住超过五分钟,看 alert log 里是不是有大的回滚段在恢复,这时候不要直接kill -9,那会让下次启动多做一次实例恢复,反而更慢。
ps -ef那一步的输出应该是空的。如果还有ora_pmon_orcl在,说明库没关干净;如果有tnslsnr在,说明监听没停。这两种情况下继续 apply,多半会在CheckActiveFilesAndExecutables那一步被拦下。
单机环境到这一步就够了。RAC 环境要把每个节点的实例和监听都停掉,或者用-local逐节点滚动:先停节点一,打节点一,起节点一,再停节点二,以此类推。滚动打补丁期间数据库整体可用,但catbundle.sql只能在一个节点跑一次,因为它改的是共享的数据字典。
4.2 opatch apply 的参数取舍与输出解读
opatch apply有几个参数值得记住,用对了能省很多交互和等待。
cd /u01/stage/p20760997/20760997 # 先干跑一次,只看它会做什么,不落盘 $ORACLE_HOME/OPatch/opatch apply -report # 正式应用,-silent 免交互,适合脚本化 $ORACLE_HOME/OPatch/opatch apply -silent # RAC 逐节点时加 -local,只处理本机 # $ORACLE_HOME/OPatch/opatch apply -local -silent-report是很多人不知道的参数,它会把补丁将要改动的文件、要执行的脚本全列出来,但不实际修改任何东西。在正式 apply 之前干跑一遍,等于把黑匣子提前打开看一眼。-silent则跳过“是否继续”的交互提示,适合写进自动化脚本;手工操作时如果不加,opatch 会停下来等你输入y,隔着屏幕容易误以为卡死。
输出里要盯三处:一是中间出现的ApplySession applying interim patch后面跟的补丁号,确认是 20760997;二是靠近结尾的OPatch succeeded.;三是日志路径,一般在$ORACLE_HOME/cfgtoollogs/opatch/下,文件名带时间戳。如果结尾是OPatch failed with error code N,别急着重跑,先去日志里搜ERROR和failed,错误码对应的原因在日志里都写清楚了。
# 出错后第一时间看日志,比反复重试有用 ls -lt $ORACLE_HOME/cfgtoollogs/opatch/ | head -5 grep -nE "ERROR|failed|Exception" $ORACLE_HOME/cfgtoollogs/opatch/opatch*.log | tail -304.3 SQL 注册:catbundle 还是 datapatch
二进制改完之后,补丁里带的 SQL 修复还没生效,必须通过脚本注册进数据字典。这一步按版本分岔:11.2.0.3 用catbundle.sql,12.1 及以后用datapatch。用错工具的结果是脚本报“找不到对象”或者干脆静默什么都不做。
# 先启库,SQL 注册需要实例处于 OPEN 状态 sqlplus -s / as sysdba <<'EOF' startup; exit EOF # 11.2.0.3 环境:跑 catbundle,参数固定为 psu apply cd $ORACLE_HOME/rdbms/admin sqlplus -s / as sysdba <<'EOF' @?/rdbms/admin/catbundle.sql psu apply exit EOFcatbundle.sql的两个参数不能省:psu表示按 PSU 方式注册,apply表示执行而不是只生成脚本。脚本运行期间会在当前目录生成catbundle_*.log,这个日志必须留着,后面验证和排错都靠它。运行时长看库的大小,小库几分钟,组件多的大库十几分钟很正常。
# 12.1 及以后的环境改用 datapatch,-verbose 输出每个补丁的注册细节 $ORACLE_HOME/OPatch/datapatch -verbosedatapatch是 12c 引入的工具,它会自己扫描$ORACLE_HOME/sqlpatch下待注册的补丁,逐个执行并记录到dba_registry_sqlpatch。-verbose建议一直加着,输出里能看到每个补丁是SUCCESS还是FAILED,比事后查表快。
RAC 环境下这两个工具都只在一个节点执行一次,不要在多个节点重复跑,重复跑会报“补丁已应用”然后跳过,虽然不致命,但日志会乱。
注意:跑完 SQL 注册后建议再执行一次
@?/rdbms/admin/utlrp.sql重编译失效对象,尤其是组件多的库。
5. 常见问题排查:五个真实翻车场景
补丁操作的报错不多,但每一条都很具体,关键在于看日志的哪一段。下面五条是我这几年实际碰到过的,按“现象、原因、解决”的顺序写,遇到同类问题可以直接对号入座。
5.1 应用阶段卡住的三个坑
坑一:CheckActiveFilesAndExecutables一直失败,提示某个.so被占用。现象是 prereq 明确报了文件名,但你用ps -ef看库已经停了。原因通常是监听没停干净,或者应用服务器上的客户端进程还连着$ORACLE_HOME下的库文件,也可能是同机另一个 Home 的进程误占。解决办法是用fuser或lsof精确定位占用者,把对应进程停掉再重试;RAC 环境还要确认另一个节点没在跑。
# 定位到底是谁占着这个文件 fuser -v $ORACLE_HOME/lib/libclntsh.so lsof $ORACLE_HOME/lib/libclntsh.so 2>/dev/null坑二:opatch apply报 error code 73,日志里是Patch conflict。现象是 apply 中途退出,提示与已安装的某个补丁冲突,日志会列出冲突的补丁号。原因是这个补丁包含的修复已经被更高版本的累积补丁覆盖,或者两个补丁改的是同一批文件。解决思路是先判断哪个更新:如果已装的是更新版本,这个包就不该打;如果确实需要,得先回滚冲突的那个补丁,或者换成合并后的补丁包。不要试图手工覆盖文件,那会把 Home 的库存记录搞乱。
坑三:opatch apply跑到一半报No space left on device。现象是进度条卡在某个百分比然后失败,日志里是写入失败。原因是 Home 所在文件系统的剩余空间不够.patch_storage留副本,或者/tmp满了导致解压临时文件写不进去。解决是先清理能清的(旧日志、旧 trace、旧补丁暂存),扩不了空间就只能先回滚再换盘。回滚前确认.patch_storage里对应补丁的目录还在,如果中途失败已经破坏了副本,就得从备份恢复 Home。
5.2 补丁装完库起不来的两个坑
坑四:库能启动,但registry$history里查不到这次补丁的记录。现象是opatch lspatches显示补丁在列,查询数据字典却没有任何 SQL 变更记录,业务上感知到的 bug 也没修。原因就是第 4.3 节说的那一步漏了,或者catbundle.sql跑的时候库不在 OPEN 状态导致中途报错退出。解决是确认库已 OPEN,重新执行@?/rdbms/admin/catbundle.sql psu apply,然后看生成的日志里有没有ERROR;如果提示“已应用”,说明记录是有的,只是查的表不对,11.2.0.3 要查registry$history而不是dba_registry_sqlpatch。
坑五:启动后大量对象 INVALID,或者报 ORA-04063。现象是startup完成后查询dba_objects发现失效对象数量异常,应用连上来报存储过程有错误。原因是 SQL 注册过程中途失败留下半成品,或者组件版本与补丁不匹配。解决顺序是先跑@?/rdbms/admin/utlrp.sql重编译,再查dba_registry看各组件状态是不是VALID;如果重编译也修不好,去$ORACLE_HOME/rdbms/log和$ORACLE_BASE/admin/$ORACLE_SID/下翻当时的日志定位失败点,必要时用备份恢复后重打。
-- 补丁后必查:失效对象数量和组件状态 select count(*) from dba_objects where status = 'INVALID'; select comp_id, status, version from dba_registry order by comp_id;6. 装完怎么验证:三条命令确认补丁真的落地了
补丁打完,opatch 说成功、脚本也说成功,都不算数,得自己查。验证分三层:二进制层看补丁在不在,SQL 层看字典记录有没有,运行层看库起来之后有没有异常报错。三层都过,这次操作才算闭环。
# 第一层:二进制层,确认补丁号出现在已装列表里 $ORACLE_HOME/OPatch/opatch lspatches | grep -i 20760997 # 清单里看详情,确认应用时间和描述 $ORACLE_HOME/OPatch/opatch lsinventory -detail | grep -A3 -i 20760997lspatches输出的是“补丁号 + 描述”的清单,行数不多,一眼能扫完。grep有输出说明二进制层没问题;如果没有输出但 apply 明明成功了,多半是环境变量指到了另一个 Home,回头查$ORACLE_HOME。
-- 第二层:SQL 层。11.2.0.3 查 registry$history select action_time, action, namespace, version, id, comments from registry$history where action like '%PSU%' or action like '%PATCH%' order by action_time desc; -- 12.1 及以后改查 dba_registry_sqlpatch -- select patch_id, patch_type, action, status, action_time, description -- from dba_registry_sqlpatch order by action_time desc;registry$history里最近一条记录的action_time应该就是你跑catbundle.sql的时间,comments里能看到补丁批次信息。如果时间对不上或者压根没记录,说明 SQL 注册那一步没落库,回第 4.3 节补跑。这一步是区分“装了”和“装好了”的关键,我见过太多只查lspatches就收工的情况。
第三层是运行层,看 alert log 和失效对象。库启动之后tail一下 alert log,搜ORA-和Errors in file,正常情况下应该只有启动信息没有报错;再跑一遍失效对象计数,dba_objects里INVALID的数量应该和打补丁前持平,明显变多就说明 SQL 注册有残留。
# alert log 位置随版本略有差异,常见路径如下 tail -200 $ORACLE_BASE/diag/rdbms/$ORACLE_SID/$ORACLE_SID/trace/alert_$ORACLE_SID.log \ | grep -nE "ORA-|Errors in file"最后养成一个习惯:把这次操作的lsinventory前后快照、catbundle日志、备份位置记到一张变更单上,下次再打补丁直接拿来做基线。补丁这件事最怕的不是装失败,是装完了没人说得清装到哪一步、能不能退回去。从那以后我每次动补丁之前,lsinventory -detail存档和 RMAN 备份这两步都强制走一遍,多花二十分钟,换的是出问题时能睡个整觉。希望帮到你。
本文还有配套的精品资源,点击获取