资讯详情

资讯详情

Oracle SGA修改后启动失败:spfile/pfile参数冲突恢复

简介这份文档面向 Oracle 数据库管理员与运维人员聚焦调整 SGA 参数后实例无法正常启动的应急排错场景适合需要快速定位 spfile 异常并恢复数据库的初中级 DBA 参考。压缩包仅含 1 个 docx 文件约 14KB篇幅短小但围绕故障处理组织内容。文档以一次实际恢复过程为线索先说明如何通过指定 pfile 应急启动实例再给出由 pfile 重建 spfile、修改 PFILE 中错误 SGA 参数以及备份并回滚 dbs 目录下 spfileSID.ora 三种处理路径同时保留 startup、show parameters 等命令输出便于对照判断问题根源。已有 328 人学习可作为 SGA 调整前后的检查清单和现场恢复思路参考。1. 改完 SGA 起不来八成不是内存不够是参数在打架凌晨两点把sga_target从 396M 调到 2G一条alter system回车下去shutdown之后startup就再也没回来ORA-01078、LRM-00109、ORA-00838 轮着刷屏。这是 oracle 改 sga 异常里最常见的一幕不是物理内存真的不够而是 spfile 里那串二进制参数被写成了一组互相矛盾的数实例在 nomount 阶段读参数时就被挡在门外连 pmon 都拉不起来。这份处理记录拆的就是这种场面pfile 藏在哪个目录、怎么用startup pfile把库先救活、怎么从 pfile 反建 spfile、改参数的三条约束线在哪、以及原文给的三个方法为什么顺序不能乱。适合手上管着单机或 RAC 节点的运维和 DBA也适合刚接手一套老库、连$ORACLE_HOME/dbs里哪个文件管什么还没摸清的人。2. 摸清加载链路startup 到底读了 dbs 目录下哪个文件2.1 三选一的加载顺序决定了你改的是不是真正生效的那份Linux 上敲下startup之后实例在 nomount 阶段会去$ORACLE_HOME/dbs目录里按固定顺序找参数文件先找spfile$ORACLE_SID.ora找不到再找spfile.ora再找不到才退到init$ORACLE_SID.ora。三份都找不到就是 ORA-01078 加 LRM-00109 这一对经典组合。这个顺序很关键——很多环境里initORCL.ora和spfileORCL.ora同时存在你以为自己在改文本文件实际上实例读的是二进制那份改了等于没改。spfile 是二进制格式只能用ALTER SYSTEM SET ... SCOPESPFILE或CREATE SPFILE这类语句写入不能拿 vi 去编辑pfile 是纯文本create pfile from spfile导出来的就是它。改 SGA 出问题绝大多数是这么来的一条alter system set sga_target2G scopespfile把值写进了 spfile重启时实例读到sga_target大于sga_max_size或者memory_target小于sga_max_size直接在 nomount 卡死。此时数据库还没走到 mount任何数据字典都查不了只能靠外部文件把实例救回来。原文里那份admin/SID/pfile/init.ora.8282011115435就是 dbca 建库或者某次CREATE PFILE留下的带时间戳快照。这类文件通常散落在$ORACLE_BASE/admin/$ORACLE_SID/pfile/下一份库可能躺着几十个文件名里的数字是生成时刻不是版本号。它的价值在于它是文本能看能改而且大概率保存着改坏之前的那套参数。2.2 用告警日志和文件时间戳锁定「案发前那一份」别急着startup pfile先花两分钟确认现场。第一步确认实例真的没起来ps -ef里看不到ora_pmon_进程就是彻底停了第二步翻告警日志最后几十行一定写着它为什么拒绝启动第三步按时间排序找出最近几份 pfile 候选。# 环境变量必须先对齐多实例机器上搞错 SID 是最低级的翻车 export ORACLE_SIDORCL export ORACLE_HOME/u01/app/oracle/product/11.2.0/dbhome_1 export PATH$ORACLE_HOME/bin:$PATH # 确认 pmon 是否还在有输出说明实例还活着处理思路完全不同 ps -ef | grep -v grep | grep ora_pmon_${ORACLE_SID} # 按修改时间倒序列出 pfile 目录最近的几份就是候选 ls -lt $ORACLE_BASE/admin/$ORACLE_SID/pfile/ | head -20ls -lt的输出里重点看两列修改时间和文件大小。时间戳文件名和真实 mtime 对不上的情况很常见——有人拷贝过文件mtime 会变成拷贝时间。所以宁可多挑两三份出来对比内容也不要盲信文件名里那串数字。告警日志的位置分版本11g 及以后在$ORACLE_BASE/diag/rdbms/$ORACLE_SID/$ORACLE_SID/trace/alert_$ORACLE_SID.log10g 在$ORACLE_BASE/admin/$ORACLE_SID/bdump/下。日志动辄几百兆别整篇翻用 grep 精准捞。ALERT$ORACLE_BASE/diag/rdbms/$ORACLE_SID/$ORACLE_SID/trace/alert_$ORACLE_SID.log # 捞出启动失败前后的关键行报错码 SGA 分配结果 grep -nE ORA-[0-9]{5}|LRM-[0-9]{5}|System Global Area|Starting ORACLE instance $ALERT | tail -60这段输出的读法是先找最后一条Starting ORACLE instance (normal)它后面紧跟的报错就是本次失败的真正原因再往上翻找到上一次成功启动时打印的Total System Global Area那是出事前正常工作的内存规模重建 pfile 时拿它做基准最靠谱。原文里成功启动后打印的 612368384 bytes 和 mount 状态下的 415236096 bytes 差了将近 200M这个差值本身就说明 pfile 和 spfile 里存的不是同一套参数后面第 4 章会专门讲这个差异从哪来。2.3 三个方法的适用边界别上来就选最顺手那个原文给了三条路很多人看一眼就选方法一结果在某些场景下反而多绕一圈。先把边界划清楚再动手。方法一用 pfile 启动再反建 spfile前提是这份 pfile 里的参数本身是合法的。它快一条startup pfile就能验证但如果你手上这份 pfile 是「改完之后才导出的」那它里面同样带着错误参数照样起不来只是报错从读 spfile 变成读 pfile。方法二直接改 pfile 里的错误参数适合方法一试出来还报 ORA-00823、ORA-00838 这类参数冲突的场景。它的好处是你能明确知道自己在改哪个值坏处是需要你对sga_max_size、sga_target、memory_target三者的约束关系心里有数否则改完还是错的。方法三恢复$ORACLE_HOME/dbs下的 spfile 备份是唯一能在几十秒内回到原点的方案但它严格来说不是「出事后的办法」而是「出事前就该做的动作」。没备份的时候这条路的变通做法是从告警日志里抄回上一次成功启动的参数值手工拼一份 pfile——能救但慢。先看 pfile 内容再决定走哪条这一步不能省# 只看和内存相关的行忽略那些注释和无关参数 grep -inE sga_max_size|sga_target|memory_target|memory_max_target|pga_aggregate_target|db_cache_size|shared_pool_size|large_pool_size|java_pool_size|lock_sga|pre_page_sga|use_large_pages \ $ORACLE_BASE/admin/$ORACLE_SID/pfile/init.ora.8282011115435输出里如果看到*.sga_target2147483648而*.sga_max_size415236096那就是典型的「目标值超过天花板」方法一直接走不通得先用方法二把sga_max_size提上去或者把sga_target压回来。pfile 里的参数可能带*.前缀也可能裸写grep 的时候别加锚点宽松匹配更保险。3. 用 pfile 应急启动三条命令把实例从 nomount 拉回 open3.1 先启动到 open确认 SGA 分配是否合理确认完 pfile 内容没问题就可以拉了。这一步的判断标准很直接实例能走到「数据库已经打开」说明 pfile 里的参数组合至少能过 nomount 和 mount 两道关。走不到说明 pfile 本身带着硬伤退回方法二。-- 用显式 pfile 路径启动绕开 dbs 目录下那份坏掉的 spfile 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 数据库装载完毕。 数据库已经打开。startup pfile的参数是绝对路径必须能读到且 oracle 用户有读权限。路径里不要出现 shell 通配符或引号嵌套中文环境下的单引号问题尤其容易踩。起来之后第一件事不是急着建 spfile而是核对这段Total System Global Area和你预期的差多少。原文这里显示 612M比 mount 状态下的 415M 大了将近 200M多出来的部分通常是自动分配的 buffer cache 和 shared pool——sga_target打开时Oracle 会按内部算法把 SGA 各组件撑到一个它认为合理的比例所以「目标值」和「实际分配值」本来就不会完全相等。-- 看实际分配到了哪些组件别只看总数 SQL select name, round(bytes/1024/1024, 1) as mb, resizeable 2 from v$sgainfo order by bytes desc; -- 看 pfile 里的值和当前生效值是否一致 SQL show parameter sga; SQL show parameter memory_target;v$sgainfo里resizeable为 YES 的组件才受sga_target动态调度Fixed Size 和 Redo Buffers 是钉死的。如果Redo Buffers明显偏小比如只有几百 K说明log_buffer没设或者被压过重建 spfile 之前顺手把它补回去比较省事。3.2 备份旧 spfile 再反建别在原地覆盖原文的顺序是startup pfile→create spfile from pfile→shutdown→startup mount。这个流程能跑通但有一个隐患create spfile在不带路径时默认写到$ORACLE_HOME/dbs/spfile$ORACLE_SID.ora如果那个位置已经有一份坏掉的 spfile行为取决于版本和实例状态运气不好就是覆盖或者报 ORA-32002cannot create SPFILE already in use by the instance。多花十秒钟把它挪走比事后找后悔药便宜得多。# 给坏掉的 spfile 打上时间戳后挪走保留现场 cd $ORACLE_HOME/dbs mv spfile${ORACLE_SID}.ora spfile${ORACLE_SID}.ora.bad.$(date %Y%m%d%H%M) ls -l spfile${ORACLE_SID}*这一步在实例用 pfile 启动的状态下做是安全的因为 spfile 当前根本没被打开。文件名后缀带上分钟级时间戳是为了同一天出两次事的时候还分得清哪份是哪份。-- 从 pfile 生成一份全新的 spfile写到默认路径 SQL create spfile from pfile/u01/app/oracle/admin/ORCL/pfile/init.ora.8282011115435; 文件已创建。也可以显式指定输出路径create spfile/u01/app/oracle/product/11.2.0/dbhome_1/dbs/spfileORCL.ora from pfile...。显式写路径的好处是你能一眼确认落在哪坏处是路径写错就报 ORA-27040 之类的文件创建错误。用默认路径 先挪旧文件是我更习惯的组合。创建完立刻验证文件存在且大小合理spfile 一般就几十 K如果只有 0 字节说明写的时候出了问题。ls -l $ORACLE_HOME/dbs/spfile${ORACLE_SID}.ora # 只读方式瞄一眼 spfile 里的参数名确认关键项都在不要编辑 strings $ORACLE_HOME/dbs/spfile${ORACLE_SID}.ora | grep -iE sga_target|sga_max_size|memory_targetstrings只是用来确认参数被写进去了spfile 的二进制格式带校验和手工用十六进制编辑器改一个字节都可能让整个文件失效这个念头直接掐掉。3.3 用 spfile 重启一遍才算真的修好create spfile成功不等于问题解决必须完整走一次shutdownstartup让实例从 spfile 读参数。这一步是验证不是走过场——很多参数问题在 pfile 启动时被掩盖只有走 spfile 路径才会暴露。SQL shutdown immediate; 数据库已经关闭。 已经卸载数据库。 ORACLE 例程已经关闭。 SQL startup; 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 parameter spfile; NAME TYPE VALUE --------- ----------- ------------------------------ spfile string /u01/app/oracle/product/11.2.0/dbhome_1/dbs/spfileORCL.oraVALUE非空说明实例走的是 spfile 路径修复闭环完成。如果这一列是空的说明它退回去读了init$ORACLE_SID.ora那就要检查 dbs 目录下是不是还留着一份优先级更高的 pfile 在捣乱。原文在这一步之后还查了show parameter sga输出sga_max_size396M、sga_target396M。这两个值一样大是 ASMM 的典型配置天花板和目标值对齐SGA 组件在这个总额里动态伸缩。如果你希望 SGA 能在线扩缩sga_max_size要留出余量如果追求稳定两者相等也没问题只是以后想在线加大sga_target会被天花板挡住得再重启一次。3.4 把参数落盘情况查清楚避免下次重启又回到原点修好之后补一刀检查当前生效值和 spfile 里存的值是不是同一套。这两者不一致意味着下次重启会变脸属于典型的「今天好了明天又炸」。-- 生效值 SQL show parameter sga_target; -- spfile 里存的值isspecifiedTRUE 表示显式写在文件里的项 SQL select name, value, isspecified 2 from v$spparameter 3 where name in (sga_target,sga_max_size,memory_target,pga_aggregate_target) 4 and isspecified TRUE;v$spparameter的value列如果显示的是原始字节数而不是带单位的字符串别慌这是正常现象——它记录的是字节值。把两边对照一遍一致就收工不一致就先查清楚是哪条alter system用了scopememory没落盘。4. 参数边界sga_max_size、sga_target、memory_target 谁管谁4.1 天花板和目标值先抬上限再调目标sga_max_size是 SGA 能长到的最大尺寸静态参数改完必须重启才生效。sga_target是 ASMM 的调度目标动态参数可以在线改但有一个硬约束不能超过sga_max_size。这一条就是大量 ORA-00823Specified value of sga_target greater than sga_max_size的来源也是原文那次事故最可能的直接原因——把目标值调大了天花板没动。正确的改法顺序是先抬上限、再调目标两条都写进 spfile一次重启解决-- 第一步先抬天花板静态参数只能写 spfile SQL alter system set sga_max_size2G scopespfile; -- 第二步再设目标值写 spfile等重启后生效 SQL alter system set sga_target2G scopespfile; -- 第三步重启验证 SQL shutdown immediate; SQL startup;反过来先执行alter system set sga_target2G scopeboth在sga_max_size还是 396M 的库上会当场报 ORA-00823运气好只是语句失败运气不好就是参数写了一半、库处于半改状态。这种「改一半」的现场最难受因为 spfile 里的值已经和新目标对不上了。还有一个细节容易被忽略SGA 的分配粒度是 granule小于 1G 的 SGA 通常是 4M 一个粒度1G 到 8G 之间是 16M更大是 32M不同平台和版本略有差异。所以你把sga_target设成 1000M实际分配可能是 1008M 或者 992M这不是 bug是向上或向下对齐到 granule 倍数。真要精确控制先查一下粒度SQL select name, round(bytes/1024/1024, 1) as mb 2 from v$sgainfo where name Granule Size;4.2 开了 memory_targetsga_target 就该退场11g 引入的 AMM 用memory_target一个参数统管 SGA 和 PGA配置上更省心但它和 ASMM 是互斥路线。一旦memory_target设成非零值再去单独设sga_target或pga_aggregate_target就容易撞上 ORA-00824 这类冲突报错——参数之间打架实例照样起不来。切换方向要明确不能两边都留着值-- 从 AMM 切回 ASMM先关掉 memory_target再设 sga_target SQL alter system set memory_target0 scopespfile; SQL alter system set sga_target2G scopespfile; SQL alter system set pga_aggregate_target512M scopespfile; SQL shutdown immediate; SQL startup;反方向切换ASMM 转 AMM则是先设memory_max_target再设memory_target两个都要写 spfile且memory_target不能超过memory_max_target。这个上限关系搞反报的就是 ORA-00838Specified value of MEMORY_TARGET is too small——报错信息说「太小」实际原因是它比sga_max_size还小被判定为不合法。Linux 上还有一道额外的坎用 AMM 的时候Oracle 会在/dev/shm上映射共享内存段这个挂载点默认往往只有物理内存的一半memory_target一开大就报 ORA-00845MEMORY_TARGET not supported on this system。查一下就知道df -h /dev/shm grep -i huge /proc/meminfo/dev/shm不够就调大挂载参数或者干脆放弃 AMM 走 ASMM HugePages后者在生产环境更常见因为大页能减少页表开销内存越大收益越明显。但 HugePages 又是另一个坑见下一章。4.3 scope 的三个取值决定了你的改动能活多久ALTER SYSTEM SET的scope参数只有三个值但每一个的含义差别很大改 SGA 出问题的人里至少三分之一是栽在这上面。scope 取值写入位置生效时机重启后是否保留MEMORY只改内存立即不保留回到 spfile 里的值SPFILE只改 spfile重启后保留BOTH内存和 spfile 都改立即保留静态参数sga_max_size、memory_max_target、log_buffer等只能写 SPFILE写 BOTH 会直接报 ORA-02095。动态参数三种都能用。最坑的场景是某次调优临时用scopememory把sga_target调大测了一下觉得效果不错就收工了结果下次重启回到老值业务方以为你根本没改。我的习惯是默认写scopeboth只在明确知道这是静态参数或者只想临时验证时才换。改完当天必须安排一次重启验证别等下次计划内维护才暴露问题——那时候业务方已经在盯着了。5. 避坑与排查五条把库改停机的真实记录5.1 ORA-32002旧 spfile 还在就去建新的现象create spfile from pfile...报 ORA-32002提示 spfile 正被实例使用。原因实例如果是用 spfile 启动的那个文件处于打开状态不能覆盖。虽然用startup pfile启动后一般不会撞上但有些人为了省事直接在原实例上操作就踩了。解决先shutdown immediate确认 pmon 进程消失再把旧 spfile 改名挪走改名比删除好留证据然后重新startup pfile到 nomount 或 open 状态再执行create spfile。顺序记牢挪文件 → 用 pfile 起 → 建 spfile → 重启。5.2 startup pfile 还是报参数冲突pfile 本身就是坏的现象按方法一操作startup pfile依然报 ORA-00823 或 ORA-00838实例还是起不来。原因这份 pfile 不是「改坏之前」的快照而是「改坏之后」导出的或者干脆是别人手工拼的。文件名带时间戳不代表内容正确ls -lt排第一也不代表能用。解决打开 pfile 用 grep 看那几个 SGA 参数把sga_target压到不超过sga_max_size把memory_target提到不小于sga_max_size再试。挑候选文件时多挑两三份对比找那份Total System Global Area和你记忆中的正常值对得上的。实在找不到就从告警日志里翻上一次成功启动打印的 SGA 分配值手工拼一份最小可用的 pfile——只留sga_target、pga_aggregate_target、db_name、control_files、db_block_size这几项先起来再说。5.3 ORA-00845/dev/shm 装不下你设的 memory_target现象改用 AMM 之后启动失败报 ORA-00845: MEMORY_TARGET not supported on this system。原因Linux 上 AMM 依赖/dev/shm这个 tmpfs 默认大小常常是物理内存的一半memory_target设得比它还大就起不来。解决df -h /dev/shm看一眼实际容量要么调大挂载改/etc/fstab里的size参数后重新挂载要么把memory_target降到安全范围内。生产环境我更倾向直接放弃 AMM走 ASMM 加 HugePages稳定性和可观测性都更好。5.4 ORA-27102HugePages 没配够use_large_pagesONLY 直接把门焊死现象参数看着都对sga_max_size也没超物理内存但实例就是起不来报 ORA-27102: out of memory。原因pfile 或 spfile 里设了use_large_pagesONLY要求 SGA 全部走大页但系统上vm.nr_hugepages配的数量不够支撑这个 SGA 大小。Oracle 不会退而求其次用小页直接失败。解决grep HugePages /proc/meminfo看HugePages_Total和HugePages_Free按 SGA 大小除以单页大小一般是 2M算出需要多少页用sysctl vm.nr_hugepagesN调整并写进/etc/sysctl.conf。应急情况下先把use_large_pages改成FALSE或从 pfile 里注释掉让实例先起来再从容配大页。5.5 改完当时挺好下次重启回到老值现象调完 SGA 观察了一周都正常某次计划内重启后又变回原来的内存配置。原因alter system用了scopememory只改了内存没写 spfile。当时show parameter看着是新值一切正常重启就露馅。解决改完立刻用v$spparameter核对 spfile 里的值两边不一致就补一条scopespfile的语句。更省事的做法是养成习惯只要不是临时验证一律scopeboth静态参数改完在变更单上标注「需重启验证」别拖到下一次维护窗口。6. 回滚预案把 spfile 备份和恢复演练做成固定动作上面五条坑四条都能靠同一个动作绕过改之前留备份。但备份本身也有讲究——光cp一份 spfile 不够因为你不一定记得住当时改了什么恢复回来也只能回到「上一次改完」而不是「上一次改之前」。我现在固定做三件事加起来不到半分钟导一份当前生效参数的 pfile 文本、复制一份 spfile 二进制、把两份文件按日期归档。# 1. 从 spfile 导出可读的 pfile 快照带日期命名 sqlplus -S / as sysdba EOF create pfile/home/oracle/bak/init_ORCL_$(date %Y%m%d).ora from spfile; exit EOF # 2. 复制 spfile 本体保留二进制原样 cp -p $ORACLE_HOME/dbs/spfile${ORACLE_SID}.ora \ /home/oracle/bak/spfile${ORACLE_SID}.ora.$(date %Y%m%d%H%M) # 3. 顺手记下当前 SGA 分配出问题时拿来对照 sqlplus -S / as sysdba EOF select name, round(bytes/1024/1024,1) mb from v$sgainfo order by bytes desc; exit EOF注意第一段 heredoc 里的$(date ...)在单引号包裹的EOF里不会展开要么把 EOF 的引号去掉要么直接在 SQL 里写死路径。这个细节我栽过导出来的文件名里带着一串字面量美元符号。备份策略按变更频率定不用搞太复杂时机动作保留校验方式每次改 SGA 前导出 pfile 复制 spfile至少 3 份show parameter spfile确认路径每月例行归档一次完整 dbs 目录6 个月抽查 spfile 能否strings出参数大版本升级前全库冷备 dbs 目录打包长期在测试库做一次恢复演练真正值钱的不是备份动作是演练。我见过太多环境备份文件躺了一年真出事的时候才发现路径写的是老机器的目录。每季度挑一个非生产库把 spfile 删掉走一遍「挪文件 → startup pfile → create spfile → 重启」全程掐表超过十分钟就说明流程里有环节没吃透。判断修没修好我只看两个信号show parameter spfile有值且指向预期路径v$spparameter里isspecifiedTRUE的那几项和show parameter的结果对得上。两个都对才敢把工单关掉。从那以后我每次敲alter system set ... scopespfile之前都会先把 pfile 导出来、spfile 复制一份两个动作十秒钟但能把一次凌晨的加班挡在门外。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →