Oracle改SGA起不来:spfile与pfile恢复实战
简介围绕 Oracle SGA 参数调整后实例无法启动这一典型故障这份 docx 文档整理了成因判断与三套可落地的恢复路径面向具备一定 Oracle 基础的 DBA 与运维人员也适合正在练习数据库故障排查的学习者参考。文档先说明 SGA 对内存分配和实例启动的影响再给出具体做法用 startup pfile 指定初始化文件应急启动确认 spfile 存在问题后通过 create spfile from pfile 重建或用 show parameters 核对 sga_max_size、sga_target 等取值并修正 PFILE 中的错误参数以及在改动前备份 dbs 目录下的 spfileSID.ora 以便回滚。压缩包内仅 1 个 docx 文件约 14KB篇幅精炼属于可对照执行的排错笔记附带的命令与返回结果便于快速比对现象。目前已有 328 人学习下载可作为 SGA 调优踩坑时的速查参考。1. 改完 SGA 拉起不来先弄清 spfile 和 pfile 谁在给实例供参数调 SGA 参数把数据库改到起不来是 Oracle 运维里很典型的一类事故sga_max_size末尾多敲一个 0或者memory_target压过了/dev/shm的实际容量shutdown immediate之后就再也没能 openstartup一路报错停在 nomount。这类 oracle 改 sga 异常的处置窗口通常只有几分钟业务在等而 spfile 是二进制文件vi打开全是乱码没有后悔药可以吃。这套流程适合能sqlplus / as sysdba登进去、但实例死活起不来的 DBA也适合刚接手一套老库、连 pfile 放在哪个目录都要现找的开发者。下面按抢救顺序走先盘环境再拿 pfile 应急启动最后重建 spfile 并逐项验收。2. 动手前的环境盘点$ORACLE_HOME、/dev/shm 与内存余量改参数改到起不来最怕的是慌里慌张直接startup一次次失败把告警日志刷满反而看不清第一条报错。我一般先花两分钟把环境钉死实例是谁、读的哪套参数文件、机器还剩多少内存。这三件事没确认就动手后面全是瞎猜。2.1 钉死实例身份三个变量和一个进程用 oracle 用户登录别用 root 直接sqlplus否则$ORACLE_HOME和$ORACLE_SID大概率是空的连上去的可能是另一个实例。# 切到 oracle 用户环境变量必须完整 su - oracle echo ORACLE_HOME$ORACLE_HOME echo ORACLE_SID$ORACLE_SID # 看实例是否还有影子进程有 pmon 说明实例未完全死透 ps -ef | grep -w pmon | grep -v grep # 客户端版本用来比对后面报错信息的格式差异 sqlplus -v这段命令的逻辑是先确认身份再动手。$ORACLE_HOME决定dbs目录在哪$ORACLE_SID决定参数文件名是spfileORCL.ora还是spfileXXX.ora两个变量错一个后面startup pfile的路径就会指到别处。ps -ef | grep pmon有输出说明实例处于 nomount 或 mount 状态还能连进去做只读检查完全没有输出说明实例已经彻底停了只能靠 pfile 冷起。提示多实例机器上先把echo $ORACLE_SID的输出贴到记事本里后面每条命令都对照一遍SID 串台是血泪经验里最常见的一种低级翻车。2.2 确认参数文件spfile 还是 pfilestartup不带参数时Oracle 按固定顺序找参数文件spfile$ORACLE_SID.ora→spfile.ora→init$ORACLE_SID.ora→init.ora前一个找到就不看后面。所以只要dbs目录里躺着一个坏掉的 spfile你在别处改 pfile 是没用的。-- 有 VALUE 说明实例当前用的是 spfile show parameter spfile; -- 逐项列出 spfile 里显式写过的参数isspecified 为 TRUE 才是真写进去的 select name, value, display_value from v$spparameter where isspecified TRUE order by name;show parameter spfile返回空值说明实例读的是文本 pfile这种情况反而好办直接改文件重启即可。v$spparameter那条查询是定位问题的抓手SGA 相关参数sga_max_size、sga_target、memory_target、db_cache_size哪几个是显式指定的一目了然。如果memory_target有值而sga_target也有值那就是典型的 AMM 与 ASMM 混配启动时很容易触发 ORA-00838 一类的冲突。2.3 三处内存上限物理内存、/dev/shm、hugepagesSGA 起不来多数时候不是参数写错而是参数超过了机器给得起的额度。三处上限要一起看缺一处就是盲人摸象。free -m # 物理内存和可用余量 df -h /dev/shm # AMM 依赖这块临时文件系统 grep -i huge /proc/meminfo # 是否启用了大页 ipcs -lm # 系统级共享内存上限free -m看的是总盘子改过的sga_max_size不能超过「物理内存减去系统和其他进程」的余量。/dev/shm是 AMMmemory_target的硬门槛Oracle 建议这块不小于memory_target的大小容器环境里默认只有 64MB一设memory_target必炸。/proc/meminfo里的HugePages_Total若为 0 而你的库又配了use_large_pages那 SGA 会退回到普通页实际可用内存比预期小一截。ipcs -lm里的max seg size是内核允许的单个共享内存段上限超过它的 SGA 请求会在ORA-27102上撞墙。检查项命令红线判断物理内存余量free -mSGA 总量不超过 available 的 70%/dev/shm容量df -h /dev/shm开了 AMM 时需不小于memory_target大页数量grep HugePages_Total /proc/meminfo与sga_max_size不匹配时会退回普通页共享内存段上限ipcs -lmmax seg size必须大于sga_max_size2.4 先把 dbs 目录整体备份掉这一步是后面第三种恢复路线的地基也是我每次上机第一件做的事在还没开始折腾之前把$ORACLE_HOME/dbs整目录复制一份带时间戳的备份。# 先看目录里有什么spfile、密码文件、lk 文件都在这里 ls -l $ORACLE_HOME/dbs # 整目录备份-a 保留属主和权限时间戳方便回滚时辨认 mkdir -p /backup/oracle cp -a $ORACLE_HOME/dbs /backup/oracle/dbs_bak_$(date %Y%m%d%H%M)cp -a比cp -r多保留了属主和权限位这一点很关键spfile 的属主必须是 oracle权限一般是 640用 root 拷出来的文件属主是 root放回去实例照样读不了会以一种看起来和内存完全无关的方式启动失败。备份目录建议放在本地盘而不是 NFS 上实例宕机时网络存储不一定还挂得住。3. 应急启动用 pfile 把实例从 nomount 拉到 open环境盘完手里应该有确认过的$ORACLE_HOME、一份dbs备份、以及一份能用的 pfile 线索。接下来就是最短路径把库拉起来先恢复业务再谈参数治理。3.1 找到那份带时间戳的 pfileOracle 在create pfile from spfile或者安装、升级过程中会在$ORACLE_BASE/admin/$ORACLE_SID/pfile/下生成形如init.ora.8282011115435的文本文件。文件名后半段是生成时间按「月日年时分秒」拼接8282011115435拆开就是 8 月 28 日、2011 年、11 点 54 分 35 秒靠这个能判断哪份是最近一次变动前的快照。# 按修改时间倒序列出所有 pfile最新的一般在最上面 ls -lt $ORACLE_BASE/admin/$ORACLE_SID/pfile/ # 11g 之后 admin 目录可能不存在pfile 也可能只落在 dbs 下 ls -lt $ORACLE_HOME/dbs/init*.ora这两个路径是新手最容易写错的地方$ORACLE_BASE/admin/$ORACLE_SID/pfile与$ORACLE_HOME/dbs是两个不同目录前者是历史快照的堆放地后者才是startup默认查找的位置。原例里能救命的init.ora.8282011115435就在 admin 目录下所以启动时必须用完整绝对路径显式指定startup pfileinit.ora...这种相对路径只有在当前目录正好是 pfile 目录时才会生效换个会话就失效。3.2 startup pfile 把库拉起来拿到路径之后一条命令就能绕开出问题的 spfile-- 用绝对路径指定 pfile路径两侧单引号不能省 SQL startup pfile/u01/app/oracle/admin/ORCL/pfile/init.ora.8282011115435; ORACLE 例程已经启动。 Total System Global Area 612368384 bytes Fixed Size 1250428 bytes Variable Size 167775108 bytes Database Buffers 436207616 bytes Redo Buffers 7135232 bytes 数据库装载完毕。 数据库已经打开。看到「数据库已经打开」说明问题被精确定位在 spfile 上pfile 能起、spfile 不能起两套参数文件的差异就是病根。这段输出里的Total System Global Area 612368384 bytes约等于 584MB把它记下来后面重建 spfile 之后要拿来对比。pfile参数只对本次启动有效不会写进任何配置实例重启后依然会去读 spfile。所以这一步只是止血不是治疗。另外要注意用 pfile 启动的实例spfile 处于「未被占用」状态这正是下一步能顺利覆盖它的前提。3.3 用 pfile 重建 spfile实例开着的时候就可以重建因为此刻 spfile 没被任何进程持有-- 从 pfile 生成 spfile默认写到 $ORACLE_HOME/dbs/spfile$ORACLE_SID.ora SQL create spfile from pfile/u01/app/oracle/admin/ORCL/pfile/init.ora.8282011115435; 文件已创建。这条语句的语义是「把文本参数文件编译成二进制参数文件」目标路径不用写Oracle 会自动放到$ORACLE_HOME/dbs下并按spfile$ORACLE_SID.ora命名。如果此时实例正用着 spfile执行会报ORA-32002: cannot create SPFILE already being used by the instance这是设计如此不是权限问题——必须先让实例以 pfile 方式运行才有资格覆盖 spfile。注意执行前确认$ORACLE_HOME/dbs下原有 spfile 已经进了 2.4 的备份这条命令是覆盖写没有二次确认。3.4 重启走 spfile核对真正生效的值pfile 里写的参数和 spfile 里实际生效的参数不一定等价所以重建完必须重启一次用 spfile 启动并核对SQL shutdown immediate; 数据库已经关闭。 已经卸载数据库。 ORACLE 例程已经关闭。 SQL startup mount; ORACLE 例程已经启动。 Total System Global Area 415236096 bytes Fixed Size 1249296 bytes Variable Size 121638896 bytes Database Buffers 285212672 bytes Redo Buffers 7135232 bytes 数据库装载完毕。 SQL show parameters spfile; NAME TYPE VALUE ----------- ----------- ------------------------------ spfile string /u01/app/oracle/product/11.2.0/dbhome_1/dbs/spfileORCL.ora SQL show parameter sga NAME TYPE VALUE ----------------- ------------ ------------------------------ lock_sga boolean FALSE pre_page_sga boolean FALSE sga_max_size big integer 396M sga_target big integer 396M先startup mount而不是直接 open是为了在挂载阶段就能用show parameter检查参数发现不对立刻停不至于带着错误参数把库开给业务。show parameters spfile的 VALUE 有值证明实例这次确实读的是新建的 spfileshow parameter sga显示sga_max_size和sga_target都是 396M和 pfile 启动时的 584MB 差了一百多兆这个偏差必须盯住它说明两套参数文件的内容并不完全等价pfile 里少写了某些内存参数实例在那种情况下回落到了默认值。确认无误再alter database open;。到这一步库已经活着但事情没完——参数口径对不齐下次重启还会再来一次。4. 备选路线手改 pfile 与回滚 spfileSID.ora生产环境不一定总能走「pfile 起库再重建」这条路。比如 pfile 本身就是坏的或者根本没有可用的历史快照那就得换招。原例给的另外两条路各有适用面选错方向会白折腾一轮。4.1 方法二直接把 pfile 里错的 SGA 参数改对如果已经定位到是某一行参数写错最直接的做法是编辑文本文件。pfile 是纯文本可以vi打开这一点是 spfile 比不了的。# 先备份再编辑别在原文件上直接改 cp $ORACLE_BASE/admin/$ORACLE_SID/pfile/init.ora.8282011115435 \ $ORACLE_BASE/admin/$ORACLE_SID/pfile/init.ora.bak vi $ORACLE_BASE/admin/$ORACLE_SID/pfile/init.ora.8282011115435打开后重点看三类行都是keyvalue形式不带空格# 下面几行是典型的内存参数写法单位可以是 M/G也可以写字节数 *.sga_max_size396M *.sga_target396M # *.memory_target2G # 开了 AMM 就要把 sga_target 注释掉 # *.db_cache_size... # ASMM 下这一项一般不手写参数取舍上有几条硬规则sga_max_size只能在重启后生效用scopespfile改别指望scopebothsga_target可以动态调整但上限被sga_max_size卡死设超了直接报ORA-00823memory_target和sga_target同时非零会互相打架AMM 模式下sga_target应当留空。改完先用 pfile 启动验证能 open 再create spfile from pfile固化顺序反了会把坏参数写进 spfile。提示改参数时统一用M作单位396M 写成 396 会被当成字节数或者直接报语法错这种低级失误在深夜处理故障时出现频率高得离谱。4.2 方法三把 spfileSID.ora 从备份里拉回来如果变更前做过dbs目录备份最快的路其实是整文件回滚一分钟内解决不用碰任何参数。# 第一步确保实例完全关闭运行中覆盖 spfile 会被回写覆盖 sqlplus / as sysdba SQL shutdown abort; SQL exit # 第二步用备份覆盖现有 spfile cp /backup/oracle/dbs_bak_202401151030/spfileORCL.ora $ORACLE_HOME/dbs/spfileORCL.ora # 第三步属主和权限必须改回来root 拷出来的文件 oracle 读不了 chown oracle:oinstall $ORACLE_HOME/dbs/spfileORCL.ora chmod 640 $ORACLE_HOME/dbs/spfileORCL.ora # 第四步正常启动 sqlplus / as sysdba SQL startup;shutdown abort在这里是可以接受的因为实例本来就起不来、没有干净关闭的可能abort 之后靠实例恢复即可。第二步的覆盖必须在实例关闭状态下做如果实例正在运行且用的是 spfile任何alter system都会把内存里的参数写回文件你刚拷进去的备份会被悄悄冲掉这是最隐蔽的一种翻车方式。第三步的chown和chmod也不能省属主不对时启动报的错是ORA-01078和LRM-00109看着像文件不存在实际是读不到。4.3 三条路线怎么选方法前提条件耗时风险点适用场景pfile 应急启动后重建 spfile有可用 pfile实例能进 nomount510 分钟pfile 与 spfile 参数不等价需二次核对参数改错但文件结构完好手改 pfile 参数已定位到具体错误参数1020 分钟改错另一处参数把问题换个形式留下明确知道该改成多少回滚 spfileSID.ora变更前做过 dbs 备份25 分钟备份过期回滚后丢新功能参数有备份、追求最快恢复选择顺序上我的习惯是有备份走回滚没备份走 pfile 重建两条都不通才去手改 pfile。手改的灵活性最高但对「改成多少才合适」的要求也最高没有明确的数值依据就别在这条路上试错。5. 排查五个把实例挡在 nomount 的报错SGA 改坏之后的报错有好几种长得都差不多但原因完全不同。下面按「现象 → 原因 → 解决」整理几条出现频率最高的。现象一ORA-01078: failure in processing system parameters配LRM-00109: could not open parameter file。原因是startup pfile后面的路径写错或者文件根本不在那个目录也可能是属主不是 oracle 导致读不到。解决方式是ls -l逐个字符核对路径确认文件存在且属主为 oracle相对路径一律换成绝对路径再试。现象二ORA-00823: Specified value of sga_target greater than sga_max_size。原因是sga_target被设到了sga_max_size之上这在alter system set sga_target...时很容易发生因为sga_max_size不能在线放大。解决办法是先以 pfile 方式起库把sga_max_size调到不小于sga_target的值重启后再调sga_target顺序不能反。现象三ORA-27102: out of memory。原因是 SGA 请求超过了内核允许的共享内存段上限或者/dev/shm不够大。先用ipcs -lm看max seg size再看df -h /dev/shm把sga_max_size压到两者较小值以下或者扩/dev/shm后重启实例。现象四ORA-00845: MEMORY_TARGET not supported on this system。典型出现在容器里/dev/shm默认只有 64MB而memory_target设了几个 G。解决办法二选一把/dev/shm挂载参数调大后重启容器或者干脆改用 ASMM把memory_target清空、只用sga_target。现象五ORA-32002: cannot create SPFILE already being used by the instance。原因是在实例已经用 spfile 启动的情况下执行create spfile from pfile目标文件被自己占着。解决办法是先startup pfile让实例脱离 spfile或者明确指定create spfile/tmp/spfile_new.ora from pfile...生成到别处再手工替换。现象六重建 spfile 后能起但 SGA 数值和变更前对不上。原因通常是 pfile 里少写了某些参数实例回落默认值重建时把「默认值」固化进了 spfile。解决办法是用create pfile/tmp/cur.ora from spfile;反向导出当前内容和变更前的备份逐行 diff把漏掉的参数补回去。6. 验收重建 spfile 之后必须走完的四步核对库能 open 只是「活着」不等于「好了」。改 SGA 的收尾动作我固定做四步少一步都可能在下一次重启时复发。第一步核对参数文件指向。show parameters spfile的 VALUE 必须指向$ORACLE_HOME/dbs/spfile$ORACLE_SID.ora指向空或者指向别处都说明实例还在用 pfile 或另一套文件此时所有参数调整都是临时的。第二步核对内存口径。三条语句一起看show parameter sga_max_size、show parameter sga_target、show parameter memory_target。要么是 AMMmemory_target非零、sga_target为空要么是 ASMMsga_max_size≥sga_target两者不能混。再用select * from v$sgainfo;看实际分配Maximum SGA Size应当等于sga_max_size。第三步重启两次。第一次从 mount 到 open 走一遍第二次完整shutdown immediate后再startup。只重启一次的话有些参数是「改了但没真正重读」第二次重启才能暴露出来。第四步看告警日志。show parameter background_dump_dest找到路径tail -100 alert_$ORACLE_SID.log扫一遍重点看有没有ORA-开头的行和Memory相关的警告SGA 勉强起得来但触到上限时日志里通常先留痕。验收项命令期望结果参数文件指向show parameters spfile指向$ORACLE_HOME/dbs下的 spfile内存模式show parameter memory_target与sga_target二选一非零实际分配select * from v$sgainfo;Maximum SGA Size与设定值一致重启稳定性shutdown immediatestartup两次都能干净 open告警日志tail -100 alert_*.log无新增 ORA- 报错从那以后我每次动 SGA 参数都强制走一遍「先create pfile留快照、再cp -a备份 dbs、改完重启两次」的流程多花十分钟换来的是出事时随时能回滚的底气。希望帮到你。本文还有配套的精品资源点击获取