ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Oracle改SGA后启动失败?用pfile/spfile快速恢复实例

Oracle改SGA后启动失败?用pfile/spfile快速恢复实例 简介Oracle DBA 在调整 SGA 相关参数如 sga_max_size、sga_target后常会遭遇数据库无法正常启动、实例中途退出等异常。这份 docx 文档正是针对此类故障编写的排错速查资料内容紧扣 Linux 环境下 Oracle 数据库的内存管理场景。文档给出三类处理办法一是使用原有 PFILE 应急启动实例再从 PFILE 重建 SPFILE二是直接修改 PFILE 中错误的 SGA 参数三是倡导在调整前备份 SPFILE 以便快速回滚。每种方法均配有实际操作命令和启动输出片段能直观看到 SGA 各内存区域的分配结果便于读者按图索骥、举一反三。压缩包共 1 个文件格式为 docx大小约 14KB体量虽小却完整覆盖故障定位、应急恢复与预防备份等环节。当前已有 326 人浏览学习适合 Oracle 运维工程师、系统管理员以及正在学习内存参数调优的数据库开发人员参考。1. 改SGA把库改挂之后先别急着重建库这个处理办法在讲什么一个常见的启动异常场景DBA执行了alter system set sga_target12G scopespfile重启之后实例起不来。这时候很多人的第一反应是“是不是数据文件坏了”甚至准备走恢复流程。其实数据库启动失败往往是因为SGA参数与参数文件、操作系统共享内存上限冲突实例在初始化内存段时就放弃了。这个处理办法的本质是围绕spfile和pfile做快速回滚用最小干预把库拉起来。适合Oracle 11g之后各版本尤其是负责生产库运维的人。下面我按“原理→诊断→恢复→避坑→验证”的顺序把整套处理路径讲清楚。2. 改SGA前必须看懂的两套参数文件spfile与pfile背后的启动异常根源2.1 为什么改SGA会改出问题写入时机与合法性校验Oracle从9i开始默认用spfile服务器参数文件它是一个二进制文件Oracle在实例运行中用alter system...scopespfile直接写而你手动维护的pfile是纯文本的initsid.ora内容是一行一个keyvalue。这两者的最大差别在于spfile会按Oracle内部的规则做“延迟校验”你执行alter system set sga_target12G scopespfile;时实例只做语法检查并不会立刻验证这个值在下一次启动时能否被操作系统分配出来。真正的合法性校验发生在实例启动阶段那时候SGA已经要按这个值去申请共享内存段一旦物理内存、内核shmmax或/dev/shm容量不够实例直接报错退出数据文件根本没机会被打开。SGA内部的参数约束也有先后顺序。sga_max_size是SGA的硬上限sga_target是动态目标sga_target原则上不能大于sga_max_size如果你把sga_target改大了却忘了同步改sga_max_size启动时Oracle会报ORA-00821。反过来sga_max_size改小到比当前sga_target还小同样启动失败。更隐蔽的是AMMAutomatic Memory Management一旦设置了memory_targetSGA和PGA共享一个总预算memory_target必须同时大于sga_target和pga_aggregate_target并且不能超过操作系统共享内存挂载点/dev/shm的大小。很多人只盯着sga_target改忽略memory_target还压在旧值上结果sga_target超过memory_target启动同样异常。所以改SGA启动异常表面上是一个参数错误实质上是“参数写入时机”和“合法性校验时机”错位——你改的时候它不查启动的时候它才较真。理解这个错位后面所有处理办法都是围绕“绕过坏spfile用可修正的pfile把实例先带起来”。2.2 常见改SGA的方式alter system命令、EMCC、直接改pfile常见做法有三种。第一种是命令行ALTER SYSTEM我在生产上最常用ALTER SYSTEM SET sga_max_size16G SCOPESPFILE; ALTER SYSTEM SET sga_target12G SCOPESPFILE;这里scope参数有三个值。scopememory只改当前运行实例重启后丢失scopespfile只写入spfile不改变当前实例下次启动生效scopeboth是立即改且写spfile。注意sga_max_size这类对当前SGA内存布局有硬约束的参数Oracle不允许scopememory直接修改因为实例已经在运行不能收缩正在使用的SGA。所以sga_max_size必须scopespfile这也意味着它一定在下次启动时才生效。很多启动异常就是从这里来的你改sga_max_size为16Gsga_target为12G但sga_max_size的spfile写入和sga_target的写入不是同一个窗口中间再次重启就出问题。第二种是EMCCEnterprise Manager Cloud Control图形化改。界面上的“Memory”页会把sga_max_size、sga_target、pga_aggregate_target一起展示改完保存时Oracle会做一轮基础校验能挡住一小部分明显错误比如sga_target大于sga_max_size但挡不住操作系统层面的资源不足。EMCC最终也是拼成ALTER SYSTEM语句下发所以它并不是“更安全”只是“更好填数”。第三种是手工编辑pfile。常见于服务器上找不到spfile的场景或者你想绕过spfile临时启动去修复。pfile是文本格式很宽松比如*.sga_target12G、sid.sga_target两种写法都行。但手工改pfile有一个坑Oracle在启动时如果没有显式指定pfile会按spfilesid.ora、spfile.ora、initsid.ora的顺序找参数文件只要存在任何一个spfile就会忽略你改好的pfile。也就是说你辛辛苦苦改了init .ora直接startup可能根本没用到它。这一点在后面的坑里我还会专门讲。三种方式对比我一般这样选日常调优用ALTER SYSTEM scopespfile改完重启最可控如果只是临时验证用pfile启动EMCC适合不熟悉命令行的同事操作但改完我一定会让它生成一条SQL日志留档。改法是否立即生效风险点适用场景alter system scopespfile否重启生效值不受当前环境校验日常调优alter system scopeboth是且持久化对sga_max_size不适用参数上下微调EMCC界面按设置项区分校验有限图形化操作手工改pfile需用pfile指定启动可能被spfile优先覆盖临时救援2.3 异常前的预防性快照备份spfile与生成pfile的标准操作每次动手改SGA之前我都会先做一次快照标准操作是登录sqlplus生成一个文本pfile再把当前SGA相关参数打出来sqlplus / as sysdba EOF create pfile/backup/init_${ORACLE_SID}_$(date %Y%m%d_%H%M).ora from spfile; show parameter sga; show parameter memory; show parameter pga; EOF这条create pfile ... from spfile会把spfile里所有非默认参数还原成一行行文本。它和直接拷贝spfile二进制文件不一样pfile是明文出问题时可以用vi、sed快速改而二进制spfile即使原样复制回去坏参数也还是坏参数。所以我一直把这个pfile叫做“后悔药”改完参数如果启动失败第一件事就是用这个备份pfile启动。备份文件生成后我还习惯把sga_max_size、sga_target、memory_target、pga_aggregate_target四个值的当前值抄在运维本上。这四个值互相牵制只记一个sga_target不够。比如你原来sga_max_size8Gsga_target6Gpga2Gmemory_target0那么改sga_target到10G时光看sga_target就会漏掉sga_max_size和memory_target两个约束这个快照就是用来对照“我到底动了哪个、漏了哪个”。如果你是在实例还没启动的状态下接手这个故障备份命令可能执行不了。没关系用第4章的办法先拉起来一次能启动到nomount就立刻做快照。注意快照文件名带上日期不要覆盖生产环境的spfile根目录经常有人同时改一个带时间戳的pfile是后续定位“谁在什么时候改了什么”的钥匙。这一步不是可有可无它在故障处理时能帮你省掉最贵的踩坑时间。3. 启动异常诊断从告警日志到现场信息收集快速定位是参数问题还是环境问题3.1 启动异常到底长什么样ORA-32004、ORA-00821、ORA-00845等关键报错改SGA后启动失败SQL*Plus通常会先抛出一个ORA错误这个错误的编号基本就锁定了方向。我把最常见的几个报错整理成一张速查表报错直接含义常见诱因ORA-00821SGA_MAX_SIZE cannot be less than SGA_TARGETsga_targetsga_max_sizeORA-00845MEMORY_TARGET not supported on this systemmemory_target/dev/shm或shmmax不足ORA-32004obsolete or deprecated parameterpfile里残留老参数如db_block_buffersORA-01078failure in processing system parameters找不到spfile/pfile或参数文件损坏ORA-27102out of memory系统共享内存段申请失败往往是shmall/shmmax不够注意区分ORA-00821和ORA-00845属于参数值与环境不匹配ORA-32004是参数过时但仍能启动ORA-01078是参数文件本身不见了。像ORA-03113连接中断在启动失败场景里也常见但它通常是进程启动到一半被系统杀掉的副产物不能单独作为依据。拿到报错后不要急着去调数据文件先在参数层面排查。还有一种情况是sqlplus提示ORA-27102时往往伴随Linux-x86_64 Error: 28: No space left on device这个“No space”不是磁盘满了而是共享内存段用尽了系统允许的shm段数量或大小方向完全不同。3.2 诊断第一步拉出alert.log里最近一次的失败原因alert.log是启动异常最直接的证据。Oracle 11g之后默认使用诊断目录ADR路径通常在$ORACLE_BASE/diag/rdbms/dbname/SID/trace/alert_SID.log10g以前在$ORACLE_HOME/rdbms/log或udump目录下。查看最近失败原因export ORACLE_BASE/u01/app/oracle tail -200 $ORACLE_BASE/diag/rdbms/${ORACLE_SID}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log | grep -E ORA-|SGA|Memory|Errors第一次看告警日志的人会被里面一行行的kkjcre1f、ksmcre吓到其实不用管它们找带ORA-前缀的行以及提到sga_target、sga_max_size、memory_target的行。比如ORA-00821出现之前日志里会先有一段MMAN进程试图调整组件大小的内部traceORA-00845出现之前日志往往先有Shared Memory相关的ksmsesg错误。把ORA错误号和上下文一起记录下来诊断就完成了大半。如果日志里只有ORA-27102: out of memory没有具体参数名再执行oerr ora 27102看详细说明并同时看操作系统消息oerr ora 27102 dmesg | tail -20dmesg里可能有Out of memory或shmget: ENOMEM这就明确指向共享内存大小问题。注意alert.log每次实例启动失败都会追加别把上一次正常启动的日志当成这次的我一般tail最后50行时间戳和当前时间对上才算数。拿到ORA号之后不要急着去百度翻译先自己对着参数关系想一想八成能看出是哪个值超了。3.3 诊断第二步核对参数文件与内存硬件上限报错方向有了再核对环境和参数文件。先看操作系统侧能不能满足SGA需求df -h /dev/shm cat /proc/meminfo | grep -E MemTotal|ShmemTotal|CommitLimit sysctl kernel.shmmax kernel.shmall kernel.shmmni解释/dev/shm是AMM的“内存来源”df显示它的当前容量kernel.shmmax是单个共享内存段的上限kernel.shmall是总共享页数上限。sga_max_size要小于shmmax且与shm page相乘后不能超过shmall。很多人以为内存总量够就够其实shmmax只是内核参数默认值可能只有32MB到2GB这时候SGA超过它就必然ORA-27102。检查这两个参数比对着Oracle报错猜更快。再看参数文件现状ls -l $ORACLE_HOME/dbs/spfile*.ora $ORACLE_HOME/dbs/init*.ora strings $ORACLE_HOME/dbs/spfile${ORACLE_SID}.ora 2/dev/null | grep -iE sga_|memory_ | headstrings的作用是直接读spfile里的明文参数名和值。spfile是二进制但参数部分以*.参数名值形式明文保存用它就能知道当前spfile里sga_max_size到底是多少不需要启动实例。如果ls找不到任何spfile只有init文件那大概率是参数文件丢失或路径不对走第4章路径三。如果strings显示的值明显比show parameter里旧值还大说明spfile被改动过且改动还没生效——这就是启动异常的根源。诊断到这一步基本可以归类是参数内部矛盾、参数文件缺失还是操作系统共享内存不足。带着这个结论去第4章选处理办法方向就不会偏。4. 处理办法用pfile/spfile把库拉起来三种路径与参数回滚操作4.1 路径一使用备份的spfile启动并回滚参数如果你按2.3的习惯做过pfile快照恢复是最快的。直接用备份的pfile启动实例sqlplus / as sysdba SQL startup pfile/backup/init_orcl_20250601_1200.ora;这条命令让Oracle忽略当前spfile改用备份参数文件初始化SGA。因为快照是在修改前生成的里面每个参数值都和上次正常启动用的一致理论上能没有任何前提地启动成功。启动后如果发现仍然有参数被改过比如alert.log提示ORA-32004说明备份文件里也残留了其他改动就继续用vi修改pfile改完用shutdown immediate再startup pfile恢复。恢复启动后下一步是让默认启动恢复成spfile。在pfile启动的实例上SQL create spfile/u01/app/oracle/product/19c/dbs/spfileorcl.ora from pfile/backup/init_orcl_20250601_1200.ora; SQL shutdown immediate; SQL startup;说明create spfile ... from pfile会把文本pfile编译回二进制spfile。这里我特意写全路径避免Oracle默认写到当前目录导致找错路径要和$ORACLE_HOME/dbs一致否则下次启动找不到。startup不带pfile参数时Oracle会优先找spfileorcl.ora所以后续自动恢复到spfile启动。整个过程不需要动数据文件如果数据文件没坏open阶段能顺利通过。这个路径的关键就是“有备份”所以我把它放在第一位也是所有处理办法里最稳的。没有备份怎么办看路径二。4.2 路径二用pfile覆盖错误参数重建spfile没有备份但spfile文件还在只是里面的SGA参数不对可以用“先从spfile导出pfile改pfile再用pfile启动”的方式绕开。注意导出操作需要实例在nomount状态但初始的spfile可能让nomount都成功不了。这时候先用最小pfile把实例带到nomountcat /tmp/init_min.ora EOF db_nameorcl processes300 sga_max_size8G sga_target8G EOF sqlplus / as sysdba SQL startup nomount pfile/tmp/init_min.ora;startup nomount pfile会用你给的最小参数建立实例的内存结构和后台进程此时不读控制文件也不读数据文件所以只要sga大小能被系统接受、db_name正确它就能起来。这里sga_max_size先给一个绝对安全的小值比如8G目的只是让实例活着。起来后再从原spfile导出完整pfileSQL create pfile/tmp/init_dump.ora from spfile; SQL shutdown abort;执行成功后/tmp/init_dump.ora就是原spfile所有非默认参数的文本形态里面包含了那个错误值。然后编辑它sed -i s/^sga_target.*/sga_target10G/ /tmp/init_dump.ora sed -i s/^sga_max_size.*/sga_max_size12G/ /tmp/init_dump.ora sqlplus / as sysdba SQL startup pfile/tmp/init_dump.ora;此时用的是修正后的完整pfile和正常启动一样会完成mount和open。确认库能正常open后把spfile重建SQL create spfile from pfile/tmp/init_dump.ora; SQL shutdown immediate; SQL startup;注意如果原spfile里sga_target写的是*.sga_target14Gsed匹配^sga_target可能匹配不到因为行首是*.。我的习惯是先grep -n sga /tmp/init_dump.ora看确切格式再sed或者直接用vi改避免这种翻车。另外最小pfile里没有写compatible、control_files等参数但create pfile from spfile导出的完整pfile里都有所以后续启动不受影响。4.3 路径三当spfile和pfile都不可用时从alert.log拼出最小初始化参数最惨的情况是spfile和pfile都丢了比如磁盘故障或误删。此时sqlplus启动直接报ORA-01078连nomount都进不去。唯一能借助的是alert.log里保存的历史信息。alert.log在每次创建控制文件或启动时会记录control_files配置在早期日志里也能看到db_name。先捞出来grep -i control_files $ORACLE_BASE/diag/rdbms/orcl/orcl/trace/alert_orcl.log | tail -3 grep -i db_name $ORACLE_BASE/diag/rdbms/orcl/orcl/trace/alert_orcl.log | tail -3然后手工拼一个最小pfilecat /tmp/init_recover.ora EOF db_nameorcl instance_nameorcl control_files/u01/app/oradata/orcl/control01.ctl,/u01/app/oradata/orcl/control02.ctl sga_max_size8G sga_target8G processes500 compatible19.0.0 EOF用这个pfile启动SQL startup pfile/tmp/init_recover.ora;如果control_files路径写对库能open。这种方式拼出的pfile省略了很多参数如undo_tablespace、db_files、log_archive_dest等它们会走默认值。对大多数标准建库来说默认值够用但如果有特殊配置后面需要对照原库的其他文档补齐。补完后记得立即create spfile from pfile把参数固化下来。这个路径是最不推荐的救急手段但比重建库快得多。4.4 启动成功后把SGA参数调回合理区间的三个参考边界不管用哪条路径把库拉起来接下来的动作都是把SGA参数落在一个不过头的区间。我给自己定的三个边界第一个边界sga_target要小于sga_max_size并且留出至少2G的余量。SGA里buffer cache、shared pool这些组件在sga_target动态调整时会在上下浮动如果sga_target和sga_max_size相等动态调优没有空间很多组件会在“需要扩展却撞上上限”的边缘反复反而不稳定。第二个边界SGA_PGA总和不超过物理内存的70%。物理内存32G的机器sga_target16G pga_aggregate_target4G合计20G约占62%相对安全如果sga_target24Gpga6G合计30G几乎吃满一旦业务并发起来操作系统为了保自己会把Oracle进程当作OOM目标。这个70%是OLTP场景的经验值纯OLAP段可以把比重往SGA偏一点但我一般仍会留出给page cache的余量。第三个边界如果用了AMMmemory_target必然同时约束SGA和PGA它不能超过/dev/shm的可用大小。检查方法df -h /dev/shm看Available列然后确保memory_target Available。否则直接报ORA-00845。这个边界很多人忽略因为平时SGA-PGA分开设置时/dev/shm只是辅助一旦开AMM就变成硬依赖。落到实际设置我通常在pfile里这样写*.sga_max_size16G *.sga_target14G *.pga_aggregate_target4G *.memory_target0写memory_target0是明确关闭AMM让SGA和PGA各自管各自的避免“sga_target改了就改不动memory_target”的连带问题。如果你需要开AMM就把memory_target设成sga_targetpga_target再上浮20%。改完用第2章的预防语句再做一次快照。5. 改SGA常见问题与避坑笔记启动异常里最容易翻车的五个场景改SGA启动异常我把它归类成“参数矛盾”“环境限制”“文件错位”“系统资源耗尽”四类。下面这五个场景是我在论坛和运维现场里反复看到的也是自己踩过坑的。它们的共同点是报错信息会误导你让你以为数据文件坏了或者监听有问题实际都和SGA参数文件相关。排查时记住一个原则——先看alert.log里的ORA号再找spfile里的当前值最后看操作系统内存参数不要一上来就去敲恢复数据文件的命令。5.1 ORA-00845MEMORY_TARGET 大于 /dev/shm现象设置memory_target或sga/pga后重启实例报ORA-00845: MEMORY_TARGET not supported on this system数据库直接拒绝启动。alert.log里通常还有一行Shutting down instance之前的内存段错误。原因Oracle的AMM通过mmap映射/dev/shm文件来放SGAPGA如果memory_target大于/dev/shm当前可用容量映射失败就报这个错。常见于虚拟机、容器默认/dev/shm只有64M或2G远小于你设的20G。解决先看df -h /dev/shm如果容量小可以remount临时扩大mount -o remount,size16G /dev/shm然后启动。如果环境不允许remount比如容器内权限不够只能改小memory_target或者直接关闭AMM用sga_max_sizesga_targetpga_aggregate_target的组合参数替代。注意如果sga和pga单独设置原则上市不使用/dev/shm的除非你打开了AMM。判断方法show parameter memory_target非0就说明AMM在管SGA和PGA。5.2 ORA-00821SGA_TARGET 大于 SGA_MAX_SIZE现象执行startup后立刻报ORA-00821: SGA_MAX_SIZE cannot be less than SGA_TARGET实例起不来。原因spfile里sga_target被改成12G但sga_max_size还是8G。或者你只改sga_max_size6G但sga_target还是8G。两个参数的校验发生在SGA初始化阶段先读sga_max_size再读sga_target发现目标值超过上限就直接抛错。解决用最小pfile启动到nomount参考4.2然后create pfile from spfile导出来把两个值改成sga_max_size12G、sga_target10G目标低于最大值再startup。确认正常后重建spfile。如果库已经在跑只想热改那么sga_target可以alter system set ... scopeboth调小而sga_max_size只能scopespfile改完必须重启才可能生效。这解释了为什么很多现场是“改完sga_max_size后重启才炸”——它本来就不支持热追平。5.3 改完pfile没指定启动仍在读spfile现象手工改了$ORACLE_HOME/dbs/initorcl.ora里的sga_targetshutdown immediate后startupshow parameter sga_target还是旧值甚至show parameter spfile显示是spfileorcl.ora。原因Oracle参数文件搜索顺序是spfile .ora优先、spfile.ora其次、最后才是init .ora。只要spfile存在你的pfile就是摆设。这也是很多新人改pfile“不生效”的真相。解决启动时显式指定startup pfile/u01/app/oracle/product/19c/dbs/initorcl.ora。或者先备份并移除spfilemv $ORACLE_HOME/dbs/spfileorcl.ora /tmp/然后startup此时才会读init文件之后再把spfile用create spfile from pfile建回来。注意移除前先确认pfile内容完整否则库也起不来。5.4 SGA调大后触发OOM实例被系统kill现象启动时实例起来了datafile也在open但运行几分钟后SQL*Plus报ORA-03113再查ps发现ora_pmon_ 进程不存在。系统dmesg -T里有Out of memory: Kill process ...alert.log最后一行没有正常shutdown标记。原因SGAPGA设置过大超过物理内存Linux OOM Killer在内存耗尽时挑中权重高的oracle进程。特别是你设置了sga_max_size内存大小、pga_aggregate_target又设得高数据库在启动时把SGA内存一次性锁进物理内存操作系统连自己的page cache都保不住。解决立即用pfile启动先把sga_target降到安全值pga也改小然后正常启动。如果业务内存确实吃紧建议用HugePages而不是盲目加大SGA。配置大页后Oracle的SGA会走2MB/1GB大页减少页表开销但大页是一把双刃剑——大页总数不够时启动照样报ORA-27102。这个坑我见过太多所以现在改SGA前一定会看cat /proc/meminfo | grep Huge。5.5 ORA-32004过时参数混在pfile里现象启动成功了但alert.log里有ORA-32004: obsolete or deprecated parameter(s) specified实例还在运行但参数管理出现混乱后续改sga_target也可能不按预期生效。原因pfile或spfile里写了老版本参数比如db_block_buffers、db_cache_buffers这些是Oracle 9i以前手工设置缓冲池个数的参数和sga_target自动共享内存管理冲突。有人从老库复制init.ora过来没删干净。解决查询哪些过时参数select name from v$parameter where isobsoleteTRUE and value is not null;或直接在alert.log看提示。然后在pfile里把对应行删掉保留sga_target、sga_max_size、pga_aggregate_target即可重建spfile。注意有些参数不算obsolete但兼容性警告比如star_transformation_enabled这类不用管只要不是和SGA管理冲突的都还好。6. 验证与预防启动跑批之后如何确认SGA改动没有留下隐患6.1 用v$parameter与v$sgastat验证生效参数重启后第一件事不是直接跑业务而是确认生效值show parameter sga; show parameter memory_target; show parameter pga_aggregate_target;再看内存分配select pool, sum(bytes)/1024/1024/1024 as gb from v$sgastat group by pool order by gb desc;如果pool为NULL的行即空内存/非组件内存占比很大说明sga_target给得太宽组件用不满如果buffer cache池接近sga_max_size上限说明sga_target可能不够。这个快照我会保留一份作为后续调优基线。6.2 观察自动调优与应急快照改完SGA后建议跑一轮代表性负载OLTP就看buffer cache命中率OLAP就看shared pool的reload次数。这些指标的SQL在网上很多但还有个更实用的即时判断查v$sga_target_advice它按不同sga_target预测物理读时间如果建议趋势线在8G以后几乎不下降说明你给的14G就是浪费可以降回10G。6.3 我的预防习惯我有几个习惯分享给做DBA的朋友一改SGA永远是先备份pfile、再改参数、再shutdown immediate二改完sga_target必然同时grep一下sga_max_size和memory_target三每次重启前用df -h /dev/shm和free -g确认容量。我自己就栽过一次开AMM时只看了物理内存总数没看/dev/shm挂载点大小结果启动直接ORA-00845最后靠备份pfile拉回十分钟解决。所以现在不管多急这三步我都不会省。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进