循序渐进Oracle:数据库管理、优化与备份恢复
上QQ阅读APP看书,第一时间看更新

1.3 数据库创建的脚本

在DBCA的最后一个步骤,如果保存生成了创建数据库的脚本,则可以通过手工执行这些脚本,在命令行完成数据库的创建工作,这可以使我们摆脱图形界面的困扰,特别是在一些不易于运行图形界面的环境。此外,很多时候通过DBCA创建数据库可能会遇到一些错误,这些错误在图形界面下可能不易判断,但是通过命令行则要容易定位得多。

1.3.1 数据库创建脚本

现在通过数据库的创建脚本来深入地了解一下数据库的创建过程。按照上面的路径找到生成的数据库创建脚本。

C:\Oracle\admin\eygle\scripts>dir

2007-01-05 15:32 <DIR> .

2007-01-05 15:32 <DIR> ..

2007-01-05 15:32 1,139 CreateDB.sql

2007-01-05 15:32 600 CreateDBCatalog.sql

2007-01-05 15:32 326 CreateDBFiles.sql

2007-01-05 15:32 253 emRepository.sql

2007-01-05 15:32 614 eygle.bat

2007-01-05 15:32 698 eygle.sql

2007-01-05 15:32 2,408 init.ora

2007-01-05 15:33 1,108 postDBCreation.sql

在Linux/UNIX环境下,同样存在这样一系列的脚本:

[oracle@jumper scripts]$ pwd

/opt/oracle/admin/eygle/scripts

[oracle@jumper scripts]$ ll

total 24

-rw-r--r-- 1 oracle dba 713 Apr 24 2006 CreateDBCatalog.sql

-rw-r--r-- 1 oracle dba 338 Apr 24 2006 CreateDBFiles.sql

-rw-r--r-- 1 oracle dba 769 Apr 24 2006 CreateDB.sql

-rwxr-xr-x 1 oracle dba 628 Aug 18 2006 eygle.sh

-rw-r--r-- 1 oracle dba 2764 Apr 24 2006 init.ora

-rw-r--r-- 1 oracle dba 442 Apr 24 2006 postDBCreation.sql

1.3.2 创建的起点

如果通过手工执行脚本来创建数据库,需要执行的脚本为 eygle.bat(在 Linux/UNIX 下是eygle.sh脚本),来看一下这个脚本的内容:

C:\Oracle\admin\eygle\scripts>type eygle.bat

mkdir C:\oracle\10.2.0\cfgtoollogs\dbca\eygle

mkdir C:\oracle\10.2.0\database

mkdir C:\oracle\admin\eygle\adump

mkdir C:\oracle\admin\eygle\bdump

mkdir C:\oracle\admin\eygle\cdump

mkdir C:\oracle\admin\eygle\dpdump

mkdir C:\oracle\admin\eygle\pfile

mkdir C:\oracle\admin\eygle\udump

mkdir C:\oracle\flash_recovery_area

mkdir C:\oracle\oradata

set ORACLE_SID=eygle

C:\oracle\10.2.0\bin\oradim.exe -new -sid EYGLE -startmode manual -spfile

C:\oracle\10.2.0\bin\oradim.exe -edit -sid EYGLE -startmode auto -srvcstart system

C:\oracle\10.2.0\bin\sqlplus /nolog @C:\oracle\admin\eygle\scripts\eygle.sql

这就是Oracle创建数据库的过程。

(1)建立一系列的目录。

注意,这里建立的 bdump 目录是 Oracle 重要的警告日志的存放地点,其缺省名称为alert_<sid>.log,我们应该定期检查该文件以发现数据库的故障或错误信息;在Oracle Database 11g中,这些文件的统一路径由参数diagnostic_dest定义。

第二个需要格外注意的是cfgtoollogs\dbca\eygle目录,在创建数据库时,主要的日志文件或输出信息会记录在该目录中,通过检查这些文件可以用来诊断创建过程中出现的一些错误。

(2)设置ORACLE_SID环境变量。

(3)通过oradim创建并配置实例。

(4)通过sqlplus运行脚本开始创建数据库。

1.3.3 ORADIM工具的使用

ORADIM工具是Oracle在Windows上的一个命令行工具,用于手工进行Oracle服务的创建、修改、删除等工作。ORADIM的使用很简单,通过帮助文件可以看到常用的命令示例,此处不再赘述。

ORADIM在数据库恢复中也常被用到,很多朋友都问过这样的问题:在Windows上,如果系统崩溃了,可能数据库软件丢掉了,但是数据文件、控制文件、日志文件等都还在,该怎样来恢复Oracle数据库?

其实过程很简单,通常只要按原来的目录结构重新安装Oracle软件,然后通过ORADIM工具重建服务,就可以启动实例、加载数据库(当然,相关的参数文件和口令文件等需要保存在$ORACLE_HOME\database目录中)。

来看以下过程,通过ORADIM创建一个服务后,实例会随之启动:

C:\>oradim -new -sid eygle

实例已创建。

用net命令可以查看系统启动了哪些服务,看到Oracle的服务已经启动:

C:\>net start

已经启动以下 Windows 服务:

...............

OracleServiceeygle 

Plug and Play

Print Spooler

命令成功完成。

如果你的系统装了一些UNIX增强工具(强烈建议在Windows上安装UNIX增强工具集,熟悉常用UNIX命令),那么可以通过grep过滤一下:

C:\>net start |grep Oracle

OracleServiceeygle

使用ORADIM工具后,会在$ORACLE_HOME\database目录下生成一个日志文件。

1.3.4 ORACLE_SID的含义

注意到在ORADIM创建服务之前,首先设置了ORACLE_SID:

setORACLE_SID=eygle

在Linux/UNIX系统的创建中,同样要设置ORACLE_SID,不过Linux/UNIX上不存在服务这项内容,实例是可以通过参数文件直接启动的(注意:启动数据库实例还和一些内核参数有关,在产品环境中需要按手册认真设定)。

看一下Linux上正常情况下启动到nomount状态的过程:

[oracle@jumper oracle]$ cd $ORACLE_HOME/dbs

[oracle@jumper dbs]$ ls

initconner.ora init.ora lkCONNER orapwconner spfileconner.ora spfile.ora

[oracle@jumper dbs]$ exportORACLE_SID=conner

[oracle@jumper dbs]$ sqlplus "/ as sysdba" 

SQL> startupnomount

ORACLE instance started.

Total System Global Area 80811208 bytes

Fixed Size 451784 bytes

Variable Size 37748736 bytes

Database Buffers 41943040 bytes

Redo Buffers 667648 bytes

注意这里,Oracle根据参数文件的内容,创建了instance,分配了相应的内存区域,启动了一组后台进程。

回顾一下前面的内容,注意到SID和ORACLE_SID已经多次出现,那么SID是什么?在数据库启动过程中又起到什么作用呢?

SID是System IDentifier的缩写,而ORACLE_SID就是Oracle System Identifier的缩写,在Oracle系统中,ORACLE_SID以环境变量的形式出现,在特定版本的Oracle软件安装(也就是ORACLE_HOME)下,当Oracle实例启动时,操作系统上fork的进程必须通过这个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/dbs(Windows上为$ORACLE_HOME\database目录)。

spfile从Oracle 9i开始引入并成为了缺省使用的参数文件,Oracle启动实例时按照以下顺序从缺省目录查找参数文件:

spfile<ORACLE_SID>.ora→spfile.ora→init<ORACLE_SID>.ora。

如果这3个文件都不存在,则Oracle实例将无法启动。

通过这些信息可以知道,在同一个ORACLE_HOME下,Oracle能够根据ORACLE_SID将实例区分开来;但是如果在不同的ORACLE_HOME下,Oracle将不屏蔽相同名称的ORACLE_SID,也就是说在同一台主机的不同ORACLE_HOME下,Oracle也是能够创建相同ORACLE_SID的实例的。

以下是一个测试。首先启动一个Oracle 8i下ORACLE_SID为eygle的实例:

$ exportORACLE_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 smon

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:Release9.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 pmon_eygle

oracle9 11180 1 0 10:24:48 ? 0:00 ora_pmon_eygle

oracle8 11084 1 0 10:24:02 ? 0:00 ora_pmon_eygle

现在这同一台主机上就启动了两个相同名称的实例,在操作系统上,Oracle能够通过ID标识将共享内存或信号量区分开来:

$ ipcs -i

IPC status from <running system> 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"

在Linux/UNIX上,一个名为oratab的文件还记录有ORACLE_SID信息。在Solaris环境中,这个文件一般位于/var/opt/oracle目录下,在Linux及其他UNIX平台,这个文件一般位于/etc目录下。

该文件的主要内容如下:

# This file is used by ORACLE utilities. It is created by root.sh

# and updated by the Database Configuration Assistant when creating a database.

# A colon, ':', is used as the field terminator. A new line terminates

# the entry. Lines beginning with a pound sign, '#', are comments.

#

# Entries are of the form:

# $ORACLE_SID:$ORACLE_HOME:<N|Y>: 

# The first and second fields are the system identifier and home

# directory of the database respectively. The third filed indicates

# to the dbstart utility that the database should , "Y", or should not,

# "N", be brought up at system boot time.

#

# Multiple entries with the same $ORACLE_SID are not allowed.

*:/opt/oracle/product/9.2.0:N 

当执行dbstart脚本时,Oracle会根据这里记录的ORACLE_SID的<N|Y>的设置来决定是否启动相关实例。

与Linux/UNIX上的情况类似,Windows上的Oracle环境也依赖于服务而存在,如图1-24所示。

图1-24 Windows上的Oracle环境依赖于服务

我们注意到 Oracle 环境的初始化是通过ORACLE.EXE eygle来完成的,至于实例和数据库是否随服务启动要依赖于注册表中的设置。

通过手动在命令行执行类似命令,可以初始化任意的Oracle应用环境,例如,以下命令就初始化了名为julia的运行时环境:

C:\>oracle julia

Press CTRL-C to exit server:

此后就可以连接到这个环境启动实例:

C:\>set ORACLE_SID=julia

C:\>set nls_lang=american_america.us7ascii

C:\>sqlplus "/ as sysdba"

SQL*Plus: Release 11.2.0.1.0 Production on Tue Aug 31 22:09:31 2010

Copyright (c) 1982, 2010, Oracle. All rights reserved.

Connected to an idle instance.

SQL> startup

ORA-01078: failure in processing system parameters

LRM-00109: 无法打开参数文件 'D:\ORACLE\11.2.0\DATABASE\INITJULIA.ORA'

当然还需要创建参数文件和口令文件等:

C:\>cp c:\oracle\10.2.0\database\SPFILEEYGLE.ORA c:\Oracle\10.2.0\database\spfilejulia.ora

C:\>orapwd file=c:\oracle\10.2.0\database\PWDjulia.ora password=oracle entries=5

此后,实例可以顺利启动,并可以挂接和打开数据库:

C:\>sqlplus "/ as sysdba"

SQL*Plus: Release 10.2.0.1.0 - Production on 星期六 2月 17 10:13:10 2007

Copyright (c) 1982, 2005, Oracle. All rights reserved.

已连接到空闲例程。

SQL> startup nomount;

ORACLE 例程已经启动。

SQL> set linesize 120

SQL> show parameter instance_name

NAME TYPE VALUE

------------------------------------ ---------------------- ---------------

instance_name string julia

SQL> show parameter db_name

NAME TYPE VALUE

------------------------------- ------------------ ------------------------------

db_name string eygle

SQL> alter database mount;

数据库已更改。

SQL> alter database open;

数据库已更改。

如果在环境窗口中按下CTRL+C组合键退出,则数据库将异常中断。

总结一下,实际上不管在Windows还是Linux/UNIX环境下,ORACLE_SID的作用就是设置一个Oracle环境窗口,通过这个环境变量来标示和命名系统进程,此后Oracle的活动可以由此展开。

1.3.5 INSTANCE_NAME的含义及作用

作为Oracle数据库的重要组成部分INSTANCE也存在一个参数标识:INSTANCE_NAME。

INSTANCE_NAME是Oracle数据库的一个参数,在参数文件中定义,用于标示数据库实例的名称,其缺省值通常就是 ORACLE_SID,但是不同的实例可以有相同的实例名。通过简单的参数文件复制,我们就可以在同一台服务器上创建多个具有相同instance_name参数设置的实例。

首先确认当前的参数文件:

bash-2.03$ cd $ORACLE_HOME/dbs

bash-2.03$ ls initeygle.ora

initeygle.ora

复制参数文件,更改名称:

bash-2.03$ cp initeygle.ora initjulia.ora

接下来通过导入新的ORACLE_SID我们就可以启动新的实例:

bash-2.03$ export ORACLE_SID=julia

bash-2.03$ sqlplus "/ as sysdba"

SQL*Plus: Release 9.2.0.4.0 - Production on Fri Feb 16 10:34:00 2007

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to an idle instance.

SQL> startup nomount;

ORACLE instance started.

现在ORACLE_SID为julia的实例已经启动,操作系统上的进程以julia名称标记:

bash-2.03$ ps -ef|grep pmon

oracle 12396 1 0 16:30 ? 00:00:00 ora_pmon_julia

oracle 16201 1 0 18:13 ? 00:00:00 ora_pmon_eygle

oracle 16256 16219 0 18:14 pts/1 00:00:00 grep pmon

但是新实例的instance_name参数设置仍然是eygle:

SQL> show parameter instance_name

NAME TYPE VALUE

------------------------------------ ---------------------- -----------------------

instance_name string eygle

总结一下,ORACLE_SID在这里用于标示进程,而instance_name则用来标示实例,两者可以具有不同的名称。但是如果不同往往带来歧义,不具备实际的意义,所以从Oracle Database 10g开始,缺省的情况下,Oracle将 instance_name这个参数从参数文件中剔除,这样就能够尽量保证ORACLE_SID和instance_name的一致。

此外Oracle的监听器(listener)配置文件中的SID_NAME就是来自instance_name参数,监听器通过instance_name才能确定需要将连接请求注册到哪一个实例上。通常listener.ora文件中SID_NAME相关设置类似如下示例:

SID_LIST_LISTENER =

(SID_DESC =

(GLOBAL_DBNAME = eygle)

(ORACLE_HOME = /opt/oracle/product/9.2.0)

(SID_NAME = eygle)

)

1.3.6 Oracle的口令文件

继续前面的脚本,在创建和启动了实例之后,Oracle开始调用eygle.sql脚本,我们将这个脚本分开来介绍。

这个脚本的最初部分是要求定义用户口令,然后使用定义的sys用户口令创建口令文件:

C:\Oracle\admin\eygle\scripts>type eygle.sql

set verify off

PROMPT specify a password for sys as parameter 1;

DEFINE sysPassword = &1

PROMPT specify a password for system as parameter 2;

DEFINE systemPassword = &2

PROMPT specify a password for sysman as parameter 3;

DEFINE sysmanPassword = &3

PROMPT specify a password for dbsnmp as parameter 4;

DEFINE dbsnmpPassword = &4

host C:\oracle\10.2.0\bin\orapwd.exe file=C:\oracle\10.2.0\database\PWDeygle.ora

password=&&sysPassword force=y

这里又引入了另外一个工具orapwd,这个工具在Linux/UNIX上同样存在,当口令文件丢失或损坏之后,可以通过这个工具重建口令文件,这个工具的语法为:

D:\oracle\11.2.0\BIN>orapwd

Usage: orapwd file=<fname> entries=<users> force=<y/n> ignorecase=<y/n> nosysdba=<y/n>

where

file - name of password file (required),

password - password for SYS will be prompted if not specified at command line,

entries - maximum number of distinct DBA (optional),

force - whether to overwrite existing file (optional),

ignorecase - passwords are case-insensitive (optional),

nosysdba - whether to shut out the SYSDBA logon (optional Database Vault only).

There must be no spaces around the equal-to (=) character.

注意:force参数是Oracle 10g中增加的,ignorecase参数是11g新增加的。

Oracle 在启动过程中,会在$ORACLE_HOME/dbs ( Windows 下相应的目录则是$ORACLE_HOME\database)目录下查找口令文件,查找的顺序是首先检查orapw<ORACLE_SID>文件,如果不存在则查找orapw文件,如果orapw文件也不存在,就会报出如下错误:

SQL> startup force;

ORACLE instance started.

ORA-01990: erroropeningpassword 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

口令文件丢失或损坏后,通常可以通过如下命令重建口令文件:

[oracle@jumper dbs]$ orapwd file=orapwhsjf password=oracle entries=5

在数据库没有启动之前,数据库内建用户是无法通过数据库来验证身份的,此时口令文件的作用就体现了出来。口令文件中存放了具有sysdba/sysoper身份用户的用户名及口令,Oracle允许用户通过口令文件验证,在数据库未启动之前登录,从而启动实例进而加载并打开数据库;而如果没有口令文件,在数据库未启动之前就只能通过操作系统认证方式来启动实例。在Oracle DataGuard环境中,要求主数据库和备用数据库的口令文件SYS用户密码相同,这时候经常会用到使用orapwd工具重建口令文件的技能。

Oracle通过一个初始化参数remote_login_passwordfile来限制口令文件的使用,通过这个参数可以设置用户登录时是否检查口令文件,以及有多少个数据库可以使用口令文件。这个参数有3个选项:EXCLUSIVE、SHARED和NONE。

当remote_login_passwordfile设置为NONE时,远程用户将不能通过sysdba/sysoper身份登录数据库:

SQL> show parameter pass

NAME TYPE VALUE

------------------------- ----------- ------------------------------

remote_login_passwordfile string NONE

此时,通过远程连接会收到如下错误:

SQL> connect sys/oracle@hsjf as sysdba

ERROR:ORA-01017: invalid username/password; logon denied

此处实际上是无法通过口令文件验证。

缺省的remote_login_passwordfile参数设置为exclusive,支持远程sysdba的登录操作:

SQL> alter system set remote_login_passwordfile=exclusive scope=spfile;

System altered.

这个参数是静态参数,修改后重启数据库才能生效。当remote_login_passwordfile参数设置为exclusive时,可以通过远程以sysdba身份登录数据库:

E:\Oracle\ora92\bin>sqlplus /nolog

SQL*Plus: Release 9.2.0.4.0 -

Production on 星期四 4月 15 09:47:11 2004

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

SQL> connect sys/oracle@hsjf as sysdba

已连接。

SQL> show user

USER 为"SYS"

当remote_login_passwordfile参数设置为shared时,则多个数据库可以共享一个口令文件,但是此时口令文件中只能存储SYS用户的口令,此时其他用户不能被授予sysdba身份:

SQL> select * from v$pwfile_users;

USERNAME SYSDB SYSOP

--------- ----- -----

SYS TRUE TRUE

SQL> grant sysdba to eygle;

grant sysdba to eygle

*

ERROR at line 1:

ORA-01994:GRANT failed: cannot addusers topublicpassword file 

SQL> show parameter password

NAME TYPE VALUE

---------------------------- ------ ------------------------------

remote_login_passwordfile string SHARED

此时的口令文件中是不能添加用户的。很多朋友的疑问在于:口令文件的缺省名称是orapw<ORACLE_SID>,怎么能够共享?

前面已经提到,Oracle数据库在启动时,首先查找的是orapw<ORACLE_SID>的口令文件,如果该文件不存在,则开始查找 orapw 的口令文件;如果同一主机上的多个数据库同时使用orapw文件,则口令文件就可以共享(当然通过其他方式,如符号链接等也可以实现共享)。

来看一下测试,首先移动缺省的口令文件:

[oracle@jumper dbs]$ mv orapweygle orapweygle.b

此时,启动数据库会出现如下错误:

SQL> startup force;

ORACLE instance started.

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

复制一个orapw口令文件,这时候再启动数据库就不会出现这个错误:

SQL> ! cp orapweygle.b orapw

SQL> startup force;

ORACLE instance started.

Database mounted.

Database opened.

SQL> show parameter password

NAME TYPE VALUE

------------------------------------ ----------- ------------------------------

remote_login_passwordfile string SHARED

那么你可能会有这样的疑问:多个 Exclusive 的数据库是否可以共享一个口令文件(orapw)呢?

继续这个测试,首先查看一下口令文件的内容,注意这里仅记录着INTERNAL/SYS的口令:

[oracle@jumper dbs]$ strings orapw

]\[Z

ORACLE Remote Password file

INTERNAL

AB27B53EDC5FEF41

8A8F025737A9097A

当REMOTE_LOGIN_PASSWORDFILE=EXCLUSIVE时:

SQL> alter system set remote_login_passwordfile=exclusive scope=spfile;

System altered.

SQL> startup force;

ORACLE instance started.

Database mounted.

Database opened.

SQL> ! stringsorapw

]\[Z

ORACLE Remote Password file

EYGLE 

INTERNAL

AB27B53EDC5FEF41

8A8F025737A9097A

注意:这里以EXCLUSIVE方式启动以后,实例名称信息被写入口令文件。

此时,如果有其他实例以Exclusive模式启动,仍然可以使用这个口令文件,口令文件中的实例名称同时被改写,也就是说,数据库只在启动过程中才读取口令文件,数据库运行过程中并不锁定该文件,类似于pfile/spfile文件。

进一步地,如果对其他用户授予SYSDBA的身份:

SQL> select * from v$pwfile_users;

USERNAME    SYSDB     SYSOP

----------------- -------- --------

SYS       TRUE     TRUE

SQL> grant sysdba to eygle;

Grant succeeded.

SQL> select * from v$pwfile_users;

USERNAME     SYSDB  SYSOP

----------------- ----- -----

SYS     TRUE     TRUE

EYGLE  TRUE  FALSE

SQL> ! strings orapw

]\[Z ORACLE Remote Password file

EYGLE

INTERNAL

AB27B53EDC5FEF41

8A8F025737A9097A

>EYGLE

B726E09FE21F8E83

注意此时增加的SYSDBA用户,其相关信息可以被写入到口令文件,一旦口令文件中增加了其他SYSDBA用户,此文件就不再能够被其他Exclusive的实例共享。

1.3.7 脚本的执行

继续来看eygle.sql的内容,接下来的脚本才是创建数据库中最关键的:

@C:\oracle\admin\eygle\scripts\CreateDB.sql

@C:\oracle\admin\eygle\scripts\CreateDBFiles.sql

@C:\oracle\admin\eygle\scripts\CreateDBCatalog.sql

@C:\oracle\admin\eygle\scripts\emRepository.sql

@C:\oracle\admin\eygle\scripts\postDBCreation.sql

第一个脚本是CreateDB.sql,其主要内容如下:

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\CreateDB.log

startup nomount pfile="C:\oracle\admin\eygle\scripts\init.ora";

CREATE DATABASE "eygle"

MAXINSTANCES 8 MAXLOGHISTORY 1 MAXLOGFILES 16 MAXLOGMEMBERS 3 MAXDATAFILES 100

DATAFILE SIZE 300M AUTOEXTEND ON NEXT 10240K MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL

SYSAUX DATAFILE SIZE 120M AUTOEXTEND ON NEXT 10240K MAXSIZE UNLIMITED

SMALLFILE DEFAULT TEMPORARY TABLESPACE TEMP TEMPFILE SIZE 20M AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED

SMALLFILE UNDO TABLESPACE "UNDOTBS1" DATAFILE SIZE 200M AUTOEXTEND ON NEXT 5120K MAXSIZE UNLIMITED

CHARACTER SETZHS16GBKNATIONAL CHARACTER SET AL16UTF16

LOGFILE GROUP 1 SIZE 51200K,GROUP 2 SIZE 51200K,GROUP 3 SIZE 51200K

USER SYS IDENTIFIED BY "&&sysPassword" USER SYSTEM IDENTIFIED BY "&&systemPassword";

set linesize 2048;

column ctl_files NEW_VALUE ctl_files;

select concat('control_files=''', concat(replace(value, ', ', ''','''), '''')) ctl_files from v$parameter wherename='control_files'; 

host "echo &ctl_files >>C:\oracle\admin\eygle\scripts\init.ora";

spool off

可以看到,这个文件的主要操作步骤如下:

(1)通过SYS连接;

(2)通过配置的参数文件init.ora启动实例;

(3)开始数据库创建;

(4)将数据库生成的控制文件名称追加到参数文件。

注意:由于选择了OMF管理文件,控制文件的名称在创建数据库之前是未知的,所以创建数据库之后才能得到名称加入参数文件中。

1.3.8 db_name参数和instance_name参数

在启动实例后执行的创建数据库中,第一个语句就是:

CREATEDATABASE"eygle"

这是数据库最重要的开始,其中"eygle"也就是图1-4中定义的数据库名称。

对于Oracle数据库来说,db_name代表数据库的名称,而instance_name代表实例的名称, instance_name通过参数文件即可修改,而db_name则不然。

我们来看一下Oracle对于数据库名称的定义:DB_NAME必须是一个不超过8个字符的文本串。在数据库创建过程中,db_name被记录在数据文件,日志文件和控制文件中。如果数据库实例启动过程中参数文件中的db_name和控制文件中的数据库名称不一致,则数据库不能启动。

通过以上定义可以看到,db_name 是最具有稳定意义的参数,在数据文件、日志文件和控制文件中都会记录数据库的名称,这个名称完全可以不同于instance_name。又由于db_name具有存储的稳定性,所以不能简单地随意更改。

以下的测试数据库拥有相同的db_name和instance_name:

[oracle@jumper oracle]$ cd $ORACLE_HOME/dbs

[oracle@jumper dbs]$ grep name initeygle.ora

*.db_name='eygle'

*.instance_name='eygle'

我们创建一个新的pfile为julia这个新的实例使用:

[oracle@jumper oracle]$ cd $ORACLE_HOME/dbs

[oracle@jumper dbs]$ cp initeygle.ora initjulia.ora

修改这个文件更改instance_name参数:

[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*Plus: Release 9.2.0.4.0 - Production on Tue Jul 25 14:04:15 2006

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

Connected to an idle instance.

SQL> startup mount;

ORACLE instance started.

ORA-01102: cannot mount database in EXCLUSIVE mode

注意,此时试图加载数据库时会出现错误,因为当前数据库被另外一个实例(eygle instance)加载。在非并行模式(OPS/RAC)下,一个数据库同时只能被一个实例加载。

此时已经启动了两个数据库实例,从后台进程可以看出:

[oracle@jumper dbs]$ ps -ef|grep ora_pmon

oracle 27321 1 0 Jul14 ? 00:00:00 ora_pmon_eygle

oracle 15445 1 0 14:04 ? 00:00:00 ora_pmon_julia

关闭eygle这个数据库实例后,就可以通过实例julia加载并打开db_name=eygle的数据库了:

[oracle@jumper dbs]$ exportORACLE_SID=julia

[oracle@jumper dbs]$ sqlplus "/ as sysdba"

SQL*Plus: Release 9.2.0.4.0 - Production on Tue Jul 25 14:05:06 2006

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

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> alterdatabaseopen;

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

新的实例具有独立的instance_name和db_name参数设置:

SQL> ! ps -ef|grep ora_pmon

oracle 15445 1 0 14:04 ? 00:00:00 ora_pmon_julia

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'

在启动过程中,我们看到,在mount阶段,数据库会对参数文件和控制文件进行比较,如果两者记录的db_name不一致,则数据库无法启动:

SQL> startup nomount;

ORACLE instance started.

SQL> alter database mount;

alter database mount

*

ERROR at line 1:

ORA-01103:databasename 'EYGLE' in controlfile isnot 'JULIA' 

关于db_name在文件头上的存储,可以通过很多方式来读取,以下通过Oracle9i中随软件提供的BBED可以最为直观的观察和理解(这一工具在Windows平台上,Oracle9i之后不再提供):

D:\oracle\9.2.0\bin>bbed

口令:blockedit

BBED: Release 2.0.0.0.0 - Limited Production on 星期二 8月 31 22:23:27 2010

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

************* !!! For Oracle Internal Use only !!! ***************

BBED> set filename 'D:\oracle\oradata\EYGLEE\DATAFILE\O1_MF_SYSTEM_60VQT1WW_.DBF'

FILENAME D:\oracle\oradata\EYGLEE\DATAFILE\O1_MF_SYSTEM_60VQT1WW_.DBF

BBED> set blocksize 8192

BLOCKSIZE 8192

BBED> setblock2

BLOCK# 2

进行了如上设置之后,我们可以检查文件头的结构信息,KCVFH是文件头信息的结构体:

BBED> p kcvfh

struct kcvfh, 360 bytes @0

struct kcvfhbfh, 20 bytes @0

ub 1 type_kcbh @0 0x0b

ub 1 frmt_kcbh @1 0xa2

ub 1 spare1_kcbh @2 0x00

ub 1 spare2_kcbh @3 0x00

ub 4 rdba_kcbh @4 0x00400001

ub 4 bas_kcbh @8 0x00000000

ub 2 wrp_kcbh @12 0x0000

ub 1 seq_kcbh @14 0x01

ub 1 flg_kcbh @15 0x04 (KCBHFCKV)

ub 2 chkval_kcbh @16 0xa837

ub 2 spare3_kcbh @18 0x0000

struct kcvfhhdr, 76 bytes @20

ub 4 kccfhswv @20 0x00000000

ub 4 kccfhcvn @24 0x0b200000

ub 4 kccfhdbi @28 0xea51005a

  text kccfhdbn[0]   @32 E 

text kccfhdbn[1]   @33 Y 

text kccfhdbn[2]   @34 G 

text kccfhdbn[3]   @35 L 

text kccfhdbn[4]   @36 E 

text kccfhdbn[5]   @37 E 

text kccfhdbn[6]   @38 

text kccfhdbn[7]   @39 

ub 4 kccfhcsq @40 0x0000064a

ub 4 kccfhfsz @44 0x00015400

s_blkz kccfhbsz @48 0x00

在以上输出中,kccfhdbn就是db_name的保留空间,共保留了8位,也正因为如此,数据库的db_name不能超过8个字符。又因为每个文件头上的实体存储,修改db_name的动作会较为复杂,一个名为NID的小工具可以用来更改数据库名称:

E:\>nid -help

DBNEWID: Release 11.2.0.2.0 - Production on 星期日 1月 23 19:52:01 2011

Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.

关键字 说明 (默认值)

----------------------------------------------------

TARGET 用户名/口令 (无)

DBNAME 新的数据库名 (无)

LOGFILE 输出日志 (无)

REVERT 还原失败的更改 否

SETNAME 仅设置新的数据库名 否

APPEND 附加至输出日志 否

HELP 显示这些消息 否

最后总结一下,一个实例(instance_name)可以mount并打开任何数据库(db_name),但是同一时间一个实例只能打开一个数据库;一个数据库(db_name)同一时间可以为任一实例(instance_name)所打开,但是在非RAC情况下,同一时间只能被同一个实例所打开。

1.3.9 sql.bsq文件与数据库创建

在CREATE DATABASE的过程中,Oracle 会调用$ORACLE_HOME/rdbms/admin/sql.bsq脚本,用于创建数据字典,这是非常重要的一个脚本,其中存储了数据字典的创建语句及注释说明。当我们对某些数据字典存在兴趣时,可以通过检查这个文件得到更为详细的信息,例如,对于控制数据库启动的bootstrap$表,其创建语句就可以从这个文件中找到:

create table bootstrap$

( line# number not null, / * statement order id * /

obj# number not null, / * object number * /

sql_text varchar2("M_VCSZ") not null) / * statement * /

storage (initial 50K) / * to avoid space management during IOR I * /

// / * "//" required for bootstrap * /

提示:sql.bsq文件值得每个接触Oracle数据的人,认真阅读理解。

sql.bsq文件的位置受到一个隐含的初始化参数(_init_sql_file)的控制:

SQL> @GetParDescrb.sql

Enter value for par: init_sql

NAME VALUE DESCRIB

--------------- ------------------ ----------------------------------------------------

_init_sql_file ?/rdbms/admin/sql.bsq File containing SQL statements to execute upon database creation

如果在数据库的创建过程中,Oracle无法找到sql.bsq文件,则数据库创建将会出错。可以测试一下移除sql.bsq文件,来看一下数据库创建过程:

SQL> startupnomount;

ORACLE instance started.

SQL>@CreateDB.sql

CREATE DATABASE eygle

*

ERROR at line 1:

ORA-01092: ORACLE instance terminated. Disconnection forced

此时警告日志(alert_<oracle_sid>.log)中会记录如下信息:

Fri Aug 18 15:45:49 2006

Errors in file /opt/oracle/admin/eygle/udump/eygle_ora_3632.trc:

ORA-01501: CREATE DATABASE failed

ORA-01526: error inopening file '?/rdbms/admin/sql.bsq' 

ORA-07391: sftopn: fopen error, unable to open text file.

Error 1526 happened during db open, shutting down database

USER: terminating instance due to error 1526

这就是sql.bsq文件在数据库创建过程中的作用。知道了这个内容之后,我们甚至可以通过手工修改sql.bsq文件来更改数据库字典对象参数,从而实现特殊要求数据库的创建或测试自定义库,也可以通过修改_init_sql_file参数来重定位sql.bsq文件的位置(但是通常这些是不建议变更的)。

sql.bsq文件中包含的数据库核心信息非常重要,在很多时候,这个文件可以帮助我们解答很多技术疑惑。

注意:在Oracle 11g中,sql.bsq文件的内容被分散隔离为多个文件。

1.3.10 数据文件及字典的创建

再来看CreateDBFiles.sql文件:

C:\Oracle\admin\eygle\scripts>type CreateDBFiles.sql

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\CreateDBFiles.log

CREATE SMALLFILE TABLESPACE "USERS" LOGGING DATAFILE SIZE 5M AUTOEXTEND ON NEXT 1280K MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO;

ALTERDATABASEDEFAULTTABLESPACE "USERS"; 

spool off

这个文件向数据库中追加了USERS表空间,并将该表空间设置为系统缺省的数据表空间,注意最后一句:

ALTER DATABASE DEFAULT TABLESPACE "USERS";

这是Oracle 10g增加的新特性,在Oracle 10g之前,如果创建用户不指定缺省的数据表空间,那么用户的缺省表空间会被指向系统表空间,增加了数据库缺省数据表空间后,如果不指定,那么创建用户的缺省数据表空间会被指向这里:

SQL> create user julia identified by eygle;

用户已创建。

SQL> select username,default_tablespace from dba_users

2 where username='JULIA';

USERNAME DEFAULT_TABLESPACE

------------------------------ ------------------------------

JULIA USERS

作为一个数据库属性,这个信息也可以从字典表props$中查询得到:

SQL> select name,value$ from props$

2 where name='DEFAULT_PERMANENT_TABLESPACE';

NAME VALUE$

------------------------------ ------------------

DEFAULT_PERMANENT_TABLESPACE USERS

继续前面的讨论,接下来Oracle通过CreateDBCatalog.sql创建数据字典:

C:\Oracle\admin\eygle\scripts>cat CreateDBCatalog.sql

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\CreateDBCatalog.log

@C:\oracle\10.2.0\rdbms\admin\catalog.sql;

@C:\oracle\10.2.0\rdbms\admin\catblock.sql;

@C:\oracle\10.2.0\rdbms\admin\catproc.sql;

@C:\oracle\10.2.0\rdbms\admin\catoctk.sql;

@C:\oracle\10.2.0\rdbms\admin\owminst.plb;

connect "SYSTEM"/"&&systemPassword"

@C:\oracle\10.2.0\sqlplus\admin\pupbld.sql;

connect "SYSTEM"/"&&systemPassword"

set echo on

spool C:\oracle\admin\eygle\scripts\sqlPlusHelp.log

@C:\oracle\10.2.0\sqlplus\admin\help\hlpbld.sql helpus.sql;

spool off

这个文件依次调用Oracle的字典创建文件等。

emRepository.sql文件是用于创建EM档案库的:

C:\Oracle\admin\eygle\scripts>type emRepository.sql

connect "SYS"/"&&sysPassword" as SYSDBA

set echo off

spool C:\oracle\admin\eygle\scripts\emRepository.log

@C:\oracle\10.2.0\sysman\admin\emdrep\sql\emreposcre C:\oracle\10.2.0 SYSMAN &&sysmanPassword TEMP ON;

WHENEVER SQLERROR CONTINUE;

spool off

最后一个执行的文件是postDBCreation.sql:

C:\Oracle\admin\eygle\scripts>cat postDBCreation.sql

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

spool C:\oracle\admin\eygle\scripts\postDBCreation.log

connect "SYS"/"&&sysPassword" as SYSDBA

set echo on

create spfile='C:\oracle\10.2.0\database\spfileeygle.ora'  FROMpfile='C:\oracle\admin\eygle\scripts\init.ora'; 

shutdown immediate;

connect "SYS"/"&&sysPassword" as SYSDBA

startup ;

alter user SYSMAN identified by "&&sysmanPassword" account unlock;

alter user DBSNMP identified by "&&dbsnmpPassword" account unlock;

select 'utl_recomp_begin: ' || to_char(sysdate, 'HH:MI:SS') from dual;

execute utl_recomp.recomp_serial();

select 'utl_recomp_end: ' || to_char(sysdate, 'HH:MI:SS') from dual;

hostC:\oracle\10.2.0\bin\emca.bat -configdbcontroldb -silent -DB_UNIQUE_NAME eygle 

-PORT1521 -EM_HOMEC:\oracle\10.2.0 -LISTENER LISTENER -SERVICE_NAME eygle 

-SYS_PWD&&sysPassword -SID eygle -ORACLE_HOMEC:\oracle\10.2.0 

-DBSNMP_PWD&&dbsnmpPassword -HOSTgqgai -LISTENER_OHC:\oracle\10.2.0 

-LOG_FILEC:\oracle\admin\eygle\scripts\emConfig.log -SYSMAN_PWD&&sysmanPassword; 

spool C:\oracle\admin\eygle\scripts\postDBCreation.log

exit;

在创建过程中,需要经历以下几个步骤后,数据库的创建才算正式完成:

(1)Oracle首先通过参数文件创建了spfile文件;

(2)解锁两个账号;

(3)编译;

(4)配置EM。