首页 > 代码库 > 转载:oracle 启动过程--oracle深入研究
转载:oracle 启动过程--oracle深入研究
Oracle数据库的启动-nomount状态深入解析
通常所说的Oracle Server主要由两个部分组成:Instance和Database。Instance是指一组后台进程(在Windows上是一组线程)和一块共享内存区域;Database是指存储在磁盘上的一组物理文件。通过Instance与Database协同,Oracle数据库才能形成一个动态的可访问关系型数据库系统。
本章将由数据库如何启动与关闭入手,开始和大家一起进入Oracle数据库的国度。
1.1 数据库的启动
从表象来看,数据库的启动极其简单,只需要以SYSDBA/SYSOPER身份登陆,敲一条startup命令既可启动数据库。然而在这条命令之后,Oracle需要执行一系列复杂的操作,深入理解这些操作不仅有助于了解Oracle数据库的运行机制,还可以在故障发生时帮助大家快速的定位问题的根源所在,所以接下来让我们一起分析一下数据库的启动过程。
Oracle数据库的启动主要包含三个步骤:
启动数据库到Nomount状态
启动数据库到Mount状态
启动数据库到Open状态
完成这三个过程,数据库才能进入就绪状态,准备提供数据访问。下面逐个来看看以上各个步骤的具体过程以及含义。
1.1.1 启动数据库到Nomount状态
在启动的第一步骤,Oracle首先寻找参数文件(pfile/spfile),然后根据参数文件中的设置(如内存分配等设置),创建实例(INSTANCE),分配内存,启动后台进程。Nomount的过程也就是启动数据库实例的过程。这个过程在后台是启动Oracle可执行程序的过程,Windows上是oracle.exe文件的初始化,在Unix/Linux上是oracle可执行文件的初始化。
Windows上Oracle11g的执行文件大小约为86M,而Linux下Oracle11g的执行文件达到145M左右:
D:\oracle\product\11.1.0\BIN>dir oracle.exe
2007-10-03 17:42 89,702,400 oracle.exe
[oracle@localhost bin]$ ls -al $ORACLE_HOME/bin/oracle
-rwsr-s--x 1 oracle dba 151901909 Jul 4 15:13 /opt/oracle/product/11.1.0/bin/oracle
在Unix/Linux上可以通过file命令查看oracle执行文件来判断Oracle是64位或是32位的,以下是Linux平台的一个示范输出,输出显示Oracle为32位:
[oracle@localhost bin]$ file $ORACLE_HOME/bin/oracle
/opt/oracle/product/11.1.0/bin/oracle: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), not stripped
在Windows上,也有可选的命令增强工具可以提供类似的功能。
了解Oracle可执行文件还有另外一个用途,在Unix/Linux上通过strings命令可以将oracle可执行文件中的字符文本转储出来,在转储的文本中可以找到很多有意思的信息,比如一些Oracle未公开的Hints信息、数据库字典基表创建信息等,类似如下一条命令可以完成这样的工作:
strings $ORACLE_HOME/bin/oracle > oracle.txt
在Nomount初始化的过程中,只要拥有了一个参数文件,就可以凭之启动实例(INSTANCE),这一步骤并不需要任何控制文件或数据文件等的参与。
1.1.1.1 实例以及进程的创建
以下是正常情况下启动到nomount状态的过程:
[oracle@eygle bdump]$ sqlplus /nolog
SQL*Plus: Release 10.2.0.1.0 - Production on Wed Jun 28 12:42:30 2006
Copyright (c) 1982, 2005, Oracle. All rights reserved.
SQL> connect / as sysdba
Connected to an idle instance.
SQL> startup nomount;
ORACLE instance started.
Total System Global Area 1073741824 bytes
Fixed Size 1223488 bytes
Variable Size 264242368 bytes
Database Buffers 801112064 bytes
Redo Buffers 7163904 bytes
注意这里,Oracle根据参数文件的内容,创建了instance,分配了相应的内存区域,启动了相应的后台进程。SGA的分配信息从以上输出中可以看到。
观察告警日志文件(alert_.log),可以看到这一阶段的启动过程:读取参数文件,应用参数启动实例。所有在参数文件中定义的非缺省参数都会记录在告警日志文件中,以下是这一过程的日志摘要示例:
Wed Jun 28 12:42:40 2006
Starting ORACLE instance (normal)
LICENSE_MAX_SESSION = 0
LICENSE_SESSIONS_WARNING = 0
Picked latch-free SCN scheme 2
Autotune of undo retention is turned on.
IMODE=BR
ILAT =18
LICENSE_MAX_USERS = 0
SYS auditing is disabled
ksdpec: called for event 13740 prior to event group initialization
Starting up ORACLE RDBMS Version: 10.2.0.1.0.
System parameters with non-default values:
processes = 150
__shared_pool_size = 255852544
__large_pool_size = 0
__java_pool_size = 4194304
__streams_pool_size = 0
sga_target = 1073741824
control_files = /opt/oracle/oradata/eygle/control01.ctl, /opt/oracle/oradata/eygle/control02.ctl, /opt/oracle/oradata/eygle/control03.ctl
db_block_size = 8192
__db_cache_size = 805306368
...............
background_dump_dest = /opt/oracle/admin/eygle/bdump
user_dump_dest = /opt/oracle/admin/eygle/udump
db_name = eygle
应用参数创建实例之后,后台进程依次启动,注意以下输出中包含了PID信息以及OS ID两个信息,PID代表该进程在数据库内部的标识符编号,而OS ID则代表该进程在操作系统上的进程编号:
PMON started with pid=2, OS id=6290
PSP0 started with pid=3, OS id=6292
MMAN started with pid=4, OS id=6294
DBW0 started with pid=5, OS id=6296
LGWR started with pid=6, OS id=6298
CKPT started with pid=7, OS id=6300
SMON started with pid=8, OS id=6302
RECO started with pid=9, OS id=6304
CJQ0 started with pid=10, OS id=6306
MMON started with pid=11, OS id=6308
MMNL started with pid=12, OS id=6310
在这里提醒大家注意一下Oracle不同版本告警日志信息的变化,在Oracle9i早期版本中,后台进程启动的日志信息里并不包含OS ID,以下是Oracle 9.2.0.4的日志信息(在Oracle 9.2.0.8中已经包含了OS ID信息):
PMON started with pid=2
DBW0 started with pid=3
LGWR started with pid=4
CKPT started with pid=5
SMON started with pid=6
RECO started with pid=7
在Oracle 11g中,这部分信息有了进一步的增强,输出中不仅包含了OS ID,而且每个后台进程的启动都有单独的时间标记(时间标记可以帮助我们判断每个后台进程启动时所消耗的时间,从而辅助进行问题诊断):
Sat Jul 05 09:53:55 2008
PMON started with pid=2, OS id=13898
Sat Jul 05 09:53:55 2008
VKTM started with pid=3, OS id=13900 at elevated priority
VKTM running at (20)ms precision
Sat Jul 05 09:53:55 2008
DIAG started with pid=4, OS id=13904
Sat Jul 05 09:53:55 2008
DBRM started with pid=5, OS id=13906
Sat Jul 05 09:53:55 2008
PSP0 started with pid=6, OS id=13908
提示:从Oracle不同版本中的变化来体会Oracle的技术进步、甚至借鉴这些变化是学习Oracle的方法之一。任何细微的变化都值得注意,认真、细致、严谨是对DBA的基本素质要求。
细心的读者朋友或许可以注意到,在前面日志里的进程启动信息里,并没有pid=1的进程,那么这个进程是否存在呢?
1.1.1.2 V$PROCESS视图
通过数据库中的v$process视图,可以找到对应于操作系统的每个进程信息:
SQL> select addr,pid,spid,username,program from v$process;
ADDR PID SPID USERNAME PROGRAM
-------- ---------- ---------- -------- ----------------------------------------
5FE162AC 1 PSEUDO
5FE16860 2 6290 oracle oracle@eygle (PMON)
5FE16E14 3 6292 oracle oracle@eygle (PSP0)
5FE173C8 4 6294 oracle oracle@eygle (MMAN)
5FE1797C 5 6296 oracle oracle@eygle (DBW0)
5FE17F30 6 6298 oracle oracle@eygle (LGWR)
5FE184E4 7 6300 oracle oracle@eygle (CKPT)
。。。。。。。。。。。。
注意以上输出,pid=1的进程是一个PSEUDO进程,这个进程被认为是初始化数据库的进程,启动其他进程之前即被占用,并在数据库中一直存在。v$process的查询输出中,SPID列代表的就是操作系统上的进程号,通过SPID可以将进程从操作系统到数据库关联起来:
[oracle@eygle bdump]$ ps -ef|grep ora_
oracle 6290 1 0 12:42 ? 00:00:00 ora_pmon_eygle
oracle 6292 1 0 12:42 ? 00:00:00 ora_psp0_eygle
oracle 6294 1 0 12:42 ? 00:00:00 ora_mman_eygle
oracle 6296 1 0 12:42 ? 00:00:00 ora_dbw0_eygle
oracle 6298 1 0 12:42 ? 00:00:00 ora_lgwr_eygle
oracle 6300 1 0 12:42 ? 00:00:00 ora_ckpt_eygle
。。。。。。。。。。。。。
如果在操作系统上发现某个进程表现异常(如占用很高的CPU资源),那么通过操作系统上的PID和V$PROCESS视图中的SPID关联,就可以找到这个OS上的进程在数据库内部的化身,从而可以进行进一步的跟踪诊断。
V$PROCESS视图包含当前数据库中活动进程的相关信息,这些进程在操作系统上都存在与之对应的OS进程。其中LATCHWAIT列代表进程当前正在等待的LATCH信息,LATCHSPIN则记录进程正在通过SPIN进行LATCH的竞争。Latch通常被称为闩,是数据库内部的串行锁机制,主要用来控制内存上的并发,在多处理器系统上,Oracle进程通过自旋(spin)来进行Latch争夺。
这个视图结构如下所示(Oracle10gR2信息):
SQL> desc v$process
Name Null? Type
----------------------------------------- -------- -------------
ADDR RAW(4)
PID NUMBER
SPID VARCHAR2(12)
USERNAME VARCHAR2(15)
SERIAL# NUMBER
TERMINAL VARCHAR2(30)
PROGRAM VARCHAR2(48)
TRACEID VARCHAR2(255)
BACKGROUND VARCHAR2(1)
LATCHWAIT VARCHAR2(8)
LATCHSPIN VARCHAR2(8)
PGA_USED_MEM NUMBER
PGA_ALLOC_MEM NUMBER
PGA_FREEABLE_MEM NUMBER
PGA_MAX_MEM NUMBER
注意这里的ADDR字段代表的是进程的地址,进程的状态等信息在内存中记录,这个ADDR记录的正是这样的内存地址信息。ADDR在数据库中(甚至是所有软件中)是非常重要的,虽然通常并不会用到,但是深入理解这些知识有助于大家更好的了解Oracle数据库。
进程的地址(Address of process)进一步的被缩写为PADDR,在V$SESSION视图中记录的PADDR就是V$PROCESS.ADDR的进一步延伸,通过两者关联,可以向数据库进一步深入。
如果向操作系统端延伸,则SPID代表的正是操作系统进程标识符(Operating system process identifier),通过SPID和OS中看到的进程PID关联,就可以建立从操作系统到数据库的关联。
所以V$PROCESS被认为是从操作系统到数据库的入口。此外,和PGA相关的几个字段则记录了进程的PGA使用情况。
1.1.1.3 参数文件的选择
接下来关注一下启动过程中Oracle选择参数文件的顺序。
从Oracle9i开始,spfile被引入Oracle数据库,Oracle首选spfile<ORACLE_SID>.ora文件作为启动参数文件;如果该文件不存在,Oracle选择spfile.ora文件;如果前两者都不存在,Oracle将会选择init<ORACLE_SID>.ora文件;如果以上三个文件都不存在,Oracle将无法创建和启动instance。Oracle在启动过程中,会在特定的路径中寻找参数文件,在Unix/Linux下的路径为$ORACLE_HOME/dbs目录,在WINDOWS上的路径为$ORACLE_HOME\database目录。
可以在SQL*PLUS中通过show parameter spfile命令来检查数据库是否使用了spfile文件,如果value不为Null,则数据库使用了spfile文件:
SQL> show parameter spfile
NAME TYPE VALUE
------- ------- -----------------------------------------------
spfile string ?/dbs/spfile@.ora
注意这里的"?"代表ORACLE_HOME,@代表数据库的sid。现在如果更名spfile<ORACLE_SID>.ora文件,此后Oracle将选择spfile.ora文件启动数据库:
[oracle@jumper dbs]$ mv spfileconner.ora spfileconner.ora.bak
SQL> startup nomount
SQL> show parameter spfile
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
spfile string ?/dbs/spfile.ora
进一步的如果再更名spfile.ora文件,此后Oracle将选择init.ora文件启动数据库:
[oracle@jumper dbs]$ mv spfile.ora spfile.ora.bak
SQL> startup nomount
SQL> show parameter spfile
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
spfile string
如果这三个文件都不存在,Oracle将无法启动:
[oracle@jumper dbs]$ mv initconner.ora initconner.ora.bak
SQL> startup
ORA-01078: failure in processing system parameters
LRM-00109: could not open parameter file ‘/opt/oracle/product/9.2.0/dbs/initconner.ora‘
注意这里出现的错误提示,报告无法找到参数文件init<ORACLE_SID>.ora,这正是Oracle在启动过程中最后一个查找的参数文件。
在Oracle整个启动过程中,参数文件是写在应用程序中的硬代码,按照前面描述的顺序进行查找,以下是来自源码中关于参数文件及其查找顺序的定义:
?/dbs/spfile@.ora
?/dbs/spfile.ora
?/dbs/init@.ora
虽然不能改变Oracle对于参数文件的搜索路径及行为,但是如果参数文件不在相应的位置,在Linux/Unix系统上,可以通过符号链接来进行重定位,以满足一些特殊需要(具体请参考第三章内容)。
1.1.1.4 实例启动最小参数需求
在参数文件中,通常需要最少的参数是db_name ,设置了这个参数之后,数据库实例就可以启动,来看一个简单的测试。
可以随意命名一个ORACLE_SID(测试来自于Linux下,适用于Linux/Unix,对于Windows平台,需要通过oradim.exe工具创建服务),然后尝试启动到nomount状态:
[oracle@jumper dbs]$ export ORACLE_SID=julia
[oracle@jumper dbs]$ sqlplus "/ as sysdba"
SQL*Plus: Release 9.2.0.4.0 - Production on Mon May 8 11:08:36 2006
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to an idle instance.
SQL> startup nomount;
ORA-01078: failure in processing system parameters
LRM-00109: could not open parameter file ‘/opt/oracle/product/9.2.0/dbs/initjulia.ora‘
参数文件查找失败会给出提示信息,此时创建一个最简单的参数文件(仅包含DB_NAME初始化参数),然后就可以启动实例:
SQL> ! echo "db_name=julia" > /opt/oracle/product/9.2.0/dbs/initjulia.ora
SQL> startup nomount;
ORACLE instance started.
Total System Global Area 97588504 bytes
Fixed Size 451864 bytes
Variable Size 46137344 bytes
Database Buffers 50331648 bytes
Redo Buffers 667648 bytes
缺省的,如果不设置,background_dump_dest目录(告警日志文件alert_<ORACLE_SID>.log的存放地点)位于$ORACLE_HOME/rdbms/log目录下:
SQL> show parameter background_dump
NAME TYPE VALUE
------------------------------------ ---------------------- ----------------------
background_dump_dest string ?/rdbms/log
顺便看下其他几个缺省路径的地点:
SQL> show parameter dump_dest
NAME TYPE VALUE
------------------------------------ ---------------------- ------------------------
background_dump_dest string ?/rdbms/log
core_dump_dest string ?/dbs
user_dump_dest string ?/rdbms/log
SQL> show parameter control_files
NAME TYPE VALUE
------------------------------------ ---------------------- -----------------------
control_files string ?/dbs/cntrl@.dbf
收录简单启动实例日志供大家参考:
[oracle@jumper dbs]$ cat $ORACLE_HOME/rdbms/log/alert_julia.log
Mon May 8 11:09:04 2006
Starting ORACLE instance (normal)
Mon May 8 11:09:04 2006
LICENSE_MAX_SESSION = 0
LICENSE_SESSIONS_WARNING = 0
SCN scheme 2
Using log_archive_dest parameter default value
LICENSE_MAX_USERS = 0
SYS auditing is disabled
Starting up ORACLE RDBMS Version: 9.2.0.4.0.
System parameters with non-default values:
db_name = julia
PMON started with pid=2
DBW0 started with pid=3
LGWR started with pid=4
CKPT started with pid=5
SMON started with pid=6
RECO started with pid=7
这样,通过以上步骤就以最少的参数需求启动了Oracle实例。
1.1.1.5 ORACLE_SID的含义
回顾一下前面的内容可以注意到,SID和ORACLE_SID已经多次出现,那么SID是什么?在数据库启动过程中又起到什么作用呢?
SID是System IDentifier的缩写,而ORACLE_SID就是Oracle System IDentifier 的缩写,在Oracle系统中,ORACLE_SID以环境变量的形式出现,当Oracle实例启动时,在操作系统上fork的进程就依据这个ORACLE_SID来创建,这就是SID的作用。
Oracle的实例(instance)是由一块共享内存区域(SGA)和一组后台进程(background processes)共同组成,而后台进程正是数据库和操作系统进行交互的通道,这些进程的名称就是通过ORACLE_SID决定的。
通过前面的讨论可以知道,实例的启动需要一个参数文件,参数文件的名称就是由ORACLE_SID决定的,对于init文件,缺省的文件名称是init<ORACLE_SID>.ora,对于spfile文件,缺省的文件名为spfile<ORACLE_SID>.ora,Oracle依据ORACLE_SID来决定和寻找参数文件启动实例。
在同一个$ORACLE_HOME下,通过参数文件,Oracle能够根据ORACLE_SID将实例区分开来;但是注意如果在不同的$ORACLE_HOME下,即使在同一台主机上,Oracle也是能够创建相同ORACLE_SID的实例的。
以下一个测试,首先启动一个Oracle8i下ORACLE_SID为eygle的实例:
$ export ORACLE_SID=eygle
$ sqlplus "/ as sysdba"
SQL*Plus: Release 8.1.7.0.0 - Production on Fri Feb 16 10:23:58 2007
(c) Copyright 2000 Oracle Corporation. All rights reserved.
Connected to an idle instance.
SQL> startup nomount;
ORACLE instance started.
SQL> ! ps -ef|grep ora_smon_eygle
oracle8 11123 11076 0 10:24:15 pts/1 0:00 grep ora_smon_eygle
oracle8 11092 1 0 10:24:02 ? 0:00 ora_smon_eygle
接下来又可以启动另外$ORACLE_HOME下ORACLE_SID为eygle的实例:
$ export ORACLE_SID=eygle
$ sqlplus "/ as sysdba"
SQL*Plus: Release 9.2.0.4.0 - Production on Fri Feb 16 10:24:43 2007
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to an idle instance.
SQL> startup nomount;
ORACLE instance started.
SQL> ! ps -ef|grep ora_smon_eygle
oracle9 11214 11172 0 10:24:58 pts/1 0:00 grep ora_smon_eygle
oracle8 11092 1 0 10:24:02 ? 0:00 ora_smon_eygle
oracle9 11188 1 0 10:24:48 ? 0:00 ora_smon_eygle
现在这同一台主机上就启动了两个相同名称的实例,在操作系统上,Oracle能够通过ID标示将共享内存或信号量区分开来:
$ ipcs -i
IPC status from as of Fri Feb 16 10:30:02 CST 2007
T ID KEY MODE OWNER GROUP
Message Queues:
q 0 0x2e781d5 --rw-r--r-- root root
T ID KEY MODE OWNER GROUP ISMATTCH
Shared Memory:
m 4096 0xabdc9b64 --rw-r----- oracle8 dba 12
m 1025 0x79552064 --rw-r----- oracle9 dba 11
Semaphores:
s 1245184 0x79978bac --ra-r----- oracle8 dba
s 458753 0xa0e9f594 --ra-r----- oracle9 dba
通过Oracle提供的一个小工具sysresv,我们可以找到对应于不同的ORACLE_SID,操作系统上创建的共享内存段ID(Shared Memory)和信号量ID(Semaphores)等信息:
$ sysresv -l eygle julia
IPC Resources for ORACLE_SID "eygle" :
Shared Memory:
ID KEY
2560 0x79552064
Semaphores:
ID KEY
720896 0xa0e9f594
Oracle Instance alive for sid "eygle"
IPC Resources for ORACLE_SID "julia" :
Shared Memory:
ID KEY
514 0xab281214
Semaphores:
ID KEY
196610 0xa7645a54
Oracle Instance alive for sid "julia"
1.1.1.6 INSTANCE_NAME的含义
在数据库内部和ORACLE_SID相关联的概念就是INSTANCE_NAME。
Oracle数据库内部存在一个初始化参数INSTANCE_NAME,用于标示数据库实例的名称,其缺省值通常就是ORACLE_SID;但是初始化参数INSTANCE_NAME和ORACLE_SID可以不同,不同实例可以拥有相同的INSTANCE_NAME。
在同一个ORACLE_HOME下,只要ORACLE_SID不同,数据库并不校验INSTANCE_NAME参数;通过简单的参数文件复制,我们就可以在同一台服务器上创建多个具有相同instance_name的实例(注意以下测试来自Oracle9i数据库):
bash-2.03$ cd $ORACLE_HOME/dbs
bash-2.03$ cp initeygle.ora initjulia.ora
bash-2.03$ export ORACLE_SID=julia
bash-2.03$ sqlplus "/ as sysdba"
SQL> startup nomount;
ORACLE instance started.
Total System Global Area 303532408 bytes
Fixed Size 731512 bytes
Variable Size 184549376 bytes
Database Buffers 117440512 bytes
Redo Buffers 811008 bytes
此时同一主机上就可以启动多个实例,ORACLE_SID不同,但是拥有了相同的instance_name:
SQL> show parameter instance_name
NAME TYPE VALUE
------------------------------------ ---------------------- -----------------------
instance_name string eygle
但是注意,在数据库内部视图V$INSTANCE中也记录着一个INSTANCE_NAME,这个INSTANCE_NAME来自数据库实例的SID,始终和ORACLE_SID保持一致,这就可能出现数据库中这两个INSTANCE_NAME不一致的情况:
SQL> select instance_name from v$instance;
INSTANCE_NAME
--------------------------------
julia
SQL> show parameter instance_name
NAME TYPE VALUE
------------------------------------ ---------------------- ------------------
instance_name string eygle
所以存在这种歧义是因为在Oracle9i中,当创建数据库进行相关配置时,数据库将INSTANCE_NAME参数写入了参数文件,这就导致了当我们修改参数文件名称变更ORACLE_SID时可能并不修改INSTANCE_NAME参数的情况;值得注意的是,从Oracle10g开始,参数文件中缺省不再记录INSTANCE_NAME,此时INSTANCE_NAME可以动态从系统获得,从而消除了以前可能常见的歧义:
D:\oracle\product>grep instance_name 9.2.0\database\SPFILEEEYGLE.ORA
*.instance_name=‘eeygle‘
D:\oracle\product>grep instance_name 10.2.0\database\SPFILEEYGLE.ORA
D:\oracle\product>grep instance_name 11.1.0\database\SPFILEEYGLEE.ORA
INSTANCE_NAME除了用来标识实例名称之外,在监听器动态注册时还会用于向监听器注册。比如在一个数据库db_name=julia,instance_name=eygle的数据库中,监听器动态注册会包含如下信息,这里的Instance内容就来自INSTANCE_NAME参数设置:
Services Summary...
Service "julia" has 1 instance(s).
Instance "eygle", status READY, has 1 handler(s) for this service...
V$INSTANCE视图和数据库实例的生命周期相关,用于显示当前实例的状态,通过这个视图可以获得包括实例的启动时间、运行主机等重要信息,通过以下一段SQL可以获得数据库的UPTIME信息:
SQL> COLUMN STARTED_AT format a25
SQL> COLUMN UPTIME format a50
SQL> SELECT TO_CHAR (startup_time, ‘DD-MON-YYYY HH24:MI:SS‘) started_at,
2 TRUNC (SYSDATE - (startup_time))
3 || ‘ day(s), ‘ || TRUNC ( 24 * ((SYSDATE - startup_time) -
4 TRUNC (SYSDATE - startup_time)))
5 || ‘ hour(s), ‘|| MOD (TRUNC ( 1440 * ( (SYSDATE - startup_time) -
6 TRUNC (SYSDATE - startup_time))),60)
7 || ‘ minute(s), ‘|| MOD (TRUNC ( 86400 * ( (SYSDATE - startup_time) -
8 TRUNC (SYSDATE - startup_time))),60)
9 || ‘ seconds‘ uptime
10 FROM v$instance;
STARTED_AT UPTIME
------------------------- --------------------------------------------------
05-JUL-2005 10:36:58 803 day(s), 2 hour(s), 27 minute(s), 55 seconds
1.1.1.7 DB_NAME与INSTANCE_NAME
相较INSTANCE_NAME参数来说,对于Oracle数据库更为重要的一个参数是DB_NAME。DB_NAME代表了实例即将挂接的数据库名称,关系到具体的物理文件。通常缺省的数据库instance_name和db_name可以设置相同(在RAC环境下,由于多个实例对应一个数据库,所以instance_name和db_name不同)。
在创建数据库的过程中,下图是用于定义数据库名称(db_name)和影响INSTANCE_NAME的SID:
Oracle文档中对于db_name的定义如下:
DB_NAME用来定义数据库名称,必须是一个不超过8个字符的文本串,在数据库创建过程中,db_name被记录在数据文件,日志文件和控制文件中。如果数据库实例启动过程中参数文件中的db_name和控制文件中的数据库名称不一致,则数据库不能启动。
此外常见的几个结论有:
1. 一个实例可以mount并打开任何数据库,但是同一时间一个实例只能打开一个数据库
2. 一个数据库可以被一个或多个实例所mount并打开(在OPS/RAC环境下,一个数据库可以被多个实例所打开)。
DB_NAME的另外一个作用是在监听器动态注册时作为缺省服务名注册,以下是Oracle10g的动态注册监听示范:
Services Summary...
Service "julia" has 1 instance(s).
Instance "eygle", status READY, has 1 handler(s) for this service...
通过下面的测试来看一下DB_NAME与数据库的关系。首先initeygle.ora文件代表了一个数据库实例:
[oracle@jumper oracle]$ cd $ORACLE_HOME/dbs
[oracle@jumper dbs]$ grep name initeygle.ora
*.db_name=‘eygle‘
*.instance_name=‘eygle‘
这个实例以及当前数据库的相关参数如下:
SQL> show parameter db_name
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_name string eygle
SQL> show parameter instance_name
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
instance_name string eygle
现在创建另外一个实例,通过复制创建一个pfile文件为名为julia这个新的实例使用:
[oracle@jumper oracle]$ cd $ORACLE_HOME/dbs
[oracle@jumper dbs]$ cp initeygle.ora initjulia.ora
[oracle@jumper dbs]$ ll init*
-rw-r--r-- 1 oracle dba 982 Jul 25 14:03 initeygle.ora
-rw-r--r-- 1 oracle dba 982 Jul 25 14:04 initjulia.ora
修改这个文件,更改instance_name参数,设置instance_name = julia,修改后的参数设置如下所示:
[oracle@jumper dbs]$ grep name initjulia.ora
*.db_name=‘eygle‘
*.instance_name=‘julia‘
现在来启动这个实例名称为julia的instance:
[oracle@jumper dbs]$ export ORACLE_SID=julia
[oracle@jumper dbs]$ sqlplus "/ as sysdba"
SQL> startup mount;
ORACLE instance started.
Total System Global Area 139531744 bytes
Fixed Size 452064 bytes
Variable Size 121634816 bytes
Database Buffers 16777216 bytes
Redo Buffers 667648 bytes
ORA-01102: cannot mount database in EXCLUSIVE mode
注意,当试图加载数据库时出现错误,因为当前数据库被另外一个实例(instance)加载。在非并行模式(Ops/RAC)下,一个数据库同时只能被一个实例加载。
此时已经启动了两个数据库实例,从后台进程可以看出:
[oracle@jumper dbs]$ ps -ef|grep dbw
oracle 27323 1 0 Jul14 ? 00:00:00 ora_dbw0_eygle
oracle 15447 1 0 14:04 ? 00:00:00 ora_dbw0_julia
oracle 25030 25000 0 18:38 pts/2 00:00:00 grep dbw
关闭eygle这个数据库实例:
[oracle@jumper dbs]$ export ORACLE_SID=eygle
[oracle@jumper dbs]$ sqlplus "/ as sysdba"
SQL> shutdown immediate;
然后就可以通过实例julia加载并打开db_name=eygle的数据库了,这也就是前面所说的,一个数据库可以被任何一个实例挂接打开(当然是有条件限制的):
[oracle@jumper dbs]$ export ORACLE_SID=julia
[oracle@jumper dbs]$ sqlplus "/ as sysdba"
SQL> alter database mount;
alter database mount
*
ERROR at line 1:
ORA-01990: error opening password file ‘/opt/oracle/product/9.2.0/dbs/orapw‘
ORA-27037: unable to obtain file status
Linux Error: 2: No such file or directory
Additional information: 3
SQL> alter database open;
Database altered.
SQL> select name from v$datafile;
NAME
----------------------------------------------------------------------------
/opt/oracle/oradata/eygle/system01.dbf
/opt/oracle/oradata/eygle/undotbs01.dbf
/opt/oracle/oradata/eygle/users01.dbf
/opt/oracle/oradata/eygle/eygle01.dbf
SQL> show parameter instance_name
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
instance_name string julia
SQL> show parameter db_name
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_name string eygle
进一步的,再来研究一下如果参数文件中的db_name和控制文件中的db_name不一致会出现什么错误。
修改参数文件中的db_name参数:
[oracle@jumper dbs]$ grep name initjulia.ora
*.db_name=‘julia‘
*.instance_name=‘julia‘
在nomount环节不存在任何问题,而在mount阶段,数据库会对参数文件和控制文件进行比较,如果两者记录的db_name不一致,则数据库无法启动,错误提示指定的数据库名称和控制文件中记录的名称不符:
SQL> startup nomount;
SQL> alter database mount;
alter database mount
*
ERROR at line 1:
ORA-01103: database name ‘EYGLE‘ in controlfile is not ‘JULIA‘
1.1.1.8 RMAN的缺省实例
在使用RMAN(Recovery Manager)时存在更为特殊的情况,Oracle允许在不存在参数文件的情况下启动一个实例,数据库的db_name会被缺省的命名为DUMMY,这是最为极端的情况,在某些恢复过程中,这个功能可以帮助我们减少很多麻烦:
[oracle@jumper dbs]$ rman target /
Recovery Manager: Release 9.2.0.4.0 - Production
Copyright (c) 1995, 2002, Oracle Corporation. All rights reserved.
connected to target database (not started)
RMAN> startup nomount;
startup failed: ORA-01078: failure in processing system parameters
LRM-00109: could not open parameter file ‘/opt/oracle/product/9.2.0/dbs/initconner.ora‘
trying to start the Oracle instance without parameter files ...
Oracle instance started
Total System Global Area 97588504 bytes
Fixed Size 451864 bytes
Variable Size 46137344 bytes
Database Buffers 50331648 bytes
Redo Buffers 667648 bytes
RMAN> host ;
[oracle@jumper dbs]$ sqlplus "/ as sysdba"
SQL*Plus: Release 9.2.0.4.0 - Production on Tue Mar 12 14:17:07 2006
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
SQL> show parameter db_name
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_name string DUMMY
此时警告日志文件中会记录如下信息:
Starting up ORACLE RDBMS Version: 9.2.0.4.0.
System parameters with non-default values:
remote_login_passwordfile= EXCLUSIVE
db_name = DUMMY
PMON started with pid=2
DBW0 started with pid=3
.....
总结一下,数据库的Nomount过程实质上就是在创建实例,这个步骤只和参数文件相关,在完成实例的创建之后,Oracle就可以逐步导航,完成数据库的加载,打开等工作。
1.1.1.9 Nomount案例两则
在创建数据库时,如果在这一步骤就出现问题,那么通常可能是系统配置(如内核参数等)存在问题,你需要检查是否分配了足够的系统资源等。
以下是一个启动到nomount状态可能会遇到的常见错误:
$ export ORACLE_SID=julia
$ sqlplus "/ as sysdba"
SQL*Plus: Release 9.2.0.4.0 - Production on Wed Feb 28 09:55:24 2007
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to an idle instance.
SQL> startup nomount;
ORA-00600: internal error code, arguments: [OSDEP_INTERNAL], [], [], [], [], [], [], []
ORA-27302: failure occurred at: skgpwreset1
ORA-27303: additional information: invalid shared ctx
ORA-27146: post/wait initialization failed
ORA-27300: OS system dependent operation:semget failed with status: 28
ORA-27301: OS failure message: No space left on device
ORA-27302: failure occurred at: sskgpsemsper
(注意:ORA-00600是Oracle内部错误的一个集合,其具体含义要看后面的参数提示,数据库出现ORA-00600错误应当引起DBA的充分重视,很多600错误可能会导致数据损失。)
在Nomount状态就出现问题,通常是系统问题,OS类错误一般说明是系统资源不足,这在Linux/Unix下和信号量等参数设置有关,多出现在同一主机运行多个数据库实例的情况(在Solaris上需要修改/etc/system文件中的内核参数,重起系统后修改生效)。在这个错误提示中,600错误的第一个参数是OSDEP_INTERNAL,我们大致可以猜测到这是一个OS Dependent/Internal Error。很多Oracle的提示可以根据缩写猜到大致的含义,但是如果是错误号那就要依赖Oracle的文档来寻找答案。
在另外一个客户现场,遭遇过另外一个案例,当时客户的服务器异常断电,当系统重新启动后,数据库无法启动(提示:重启主机对于DBA来说应当极其慎重,很多隐藏的故障可能在重启时爆发出来,在没有做好充分 之前,不要贸然从事)。
数据库的症状是,启动主机到Nomount状态后,后台进程会立即将实例中止,也就是说数据库实例都无法稳定创建,告警日志文件信息如下:
Mon Dec 3 14:24:30 2007
Errors in file /oraclehx/app/admin/sxlss/bdump/sxlss_pmon_360454.trc:
ORA-07445: exception encountered: core dump [] [] [] [] [] []
PSP0 started with pid=3, OS id=422106
MMAN started with pid=4, OS id=303332
DBW0 started with pid=5, OS id=299324
。。。。。。。。。。。。。。。。。。
SMON started with pid=11, OS id=278882
RECO started with pid=12, OS id=319898
CJQ0 started with pid=13, OS id=295404
MMON started with pid=14, OS id=303428
MMNL started with pid=15, OS id=438776
Mon Dec 3 14:24:33 2007
PSP0: terminating instance due to error 472
Instance terminated by PSP0, pid = 422106
综合前面介绍的知识,如果实例都无法创建,那通常是在OS方面存在问题,这些问题在系统重新启动后才体现出来,经过检查,发现客户系统是AIX操作系统补丁应用不完全,最后导致了数据库无法启动,应用完整的系统补丁后,数据库恢复正常:
instfix -i|grep ML
All filesets for 5.3.0.0_AIX_ML were found.
All filesets for 5300-01_AIX_ML were found.
All filesets for 5300-02_AIX_ML were found.
All filesets for 5300-03_AIX_ML were found.
All filesets for 5300-04_AIX_ML were found.
All filesets for 5300-05_AIX_ML were found.
Not all filesets for 5300-06_AIX_ML were found.
这个案例给我们的经验是,当进行OS补丁应用时一定要认真确认,对关键补丁应当进行服务器重启验证,不能掉以轻心。
作者:eygle |English 【转载时请标明出处和作者信息】|【恩墨学院 OCM培训传DBA成功之道】
链接:http://www.eygle.com/archives/2008/12/oracle_internals_startup_nomount.html
转载:oracle 启动过程--oracle深入研究