深入解析Oracle:数据库的初始化
上QQ阅读APP看书,第一时间看更新

1.3 数据库创建的脚本

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

1.3.1 数据库创建脚本

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

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

2012-12-11 16:03 <DIR> .

2012-12-11 16:03 <DIR> ..

2012-12-11 16:03 1,204 CreateDB.sql

2012-12-11 16:03 640 CreateDBCatalog.sql

2012-12-11 16:03 398 CreateDBFiles.sql

2012-12-11 16:03 281 emRepository.sql

2012-12-11 16:03 640 eygle.bat

2012-12-11 16:03 721 eygle.sql

2012-12-11 16:03 1,659 init.ora

2012-12-11 16:03 512 lockAccount.sql

2012-12-11 16:03 944 postDBCreation.sql

9 File(s) 6,999 bytes

2 Dir(s) 579,424,256 bytes free

在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脚本),来看一下这个脚本的内容:

OLD_UMASK=`umask`

umask 0027

mkdir D:\Oracle\11.2.0\database

mkdir D:\Oracle\admin\eygle\adump

mkdir D:\Oracle\admin\eygle\dpdump

mkdir D:\Oracle\admin\eygle\pfile

mkdir D:\Oracle\cfgtoollogs\dbca\eygle

mkdir D:\Oracle\fast_recovery_area

mkdir D:\Oracle\fast_recovery_area\eygle

mkdir D:\Oracle\oradata\eygle

umask ${OLD_UMASK}

set ORACLE_SID=eygle

set PATH=%ORACLE_HOME%\bin;%PATH%

D:\Oracle\11.2.0\bin\oradim.exe -new -sid EYGLE -startmode manual -spfile

D:\Oracle\11.2.0\bin\oradim.exe -edit -sid EYGLE -startmode auto -srvcstart system

D:\Oracle\11.2.0\bin\sqlplus /nolog @D:\Oracle\admin\eygle\scripts\eygle.sql

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

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

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

(2)设置ORACLE_SID环境变量。

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

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

1.3.3 ORADIM工具的使用

ORADIM工具是Oracle在Windows上的一个命令行工具(在Linux、UNIX上无需这类工具),用于进行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:

set ORACLE_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]$ export ORACLE_SID=conner

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

SQL> startup nomount

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的实例:

$ 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 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: 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 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 either Database Configuration Assistant while creating

# a database or ASM Configuration Assistant while creating ASM instance.

# 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.

#

enmot1:/u01/app/oracle/product/11.2.0/dbhome_1:N

当配置实例随操作系统自动启动(或手工执行dbstart脚本)时,Oracle会根据这里记录的ORACLE_SID的<N|Y>的设置来决定是否启动相关实例。

与Linux/UNIX上的情况类似,Windows上的Oracle环境也依赖于服务而存在,如图1-28所示。我们注意到Oracle环境的初始化是通过执行ORACLE.EXE eygle来完成的,至于实例和数据库是否随服务启动则要依赖于注册表中的设置。

图1-28 Oracle环境依赖于服务

通过手动在命令行执行类似命令,可以初始化任意的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 Oracle的口令文件

继续前面的脚本,在创建和启动了实例之后,Oracle开始调用eygle.sql脚本,我们将这个脚本分开来介绍。这个脚本的最初部分是要求定义用户口令,然后使用定义的sys用户口令创建口令文件:

set verify off

ACCEPT sysPassword CHAR PROMPT 'Enter new password for SYS: ' HIDE

ACCEPT systemPassword CHAR PROMPT 'Enter new password for SYSTEM: ' HIDE

ACCEPT sysmanPassword CHAR PROMPT 'Enter new password for SYSMAN: ' HIDE

ACCEPT dbsnmpPassword CHAR PROMPT 'Enter new password for DBSNMP: ' HIDE

host D:\Oracle\11.2.0\bin\orapwd.exe

file=D:\Oracle\11.2.0\database\PWDeygle.ora 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参数是Oracle 11g新增加的。

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

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

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

[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 add users to public password 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> ! strings orapw

]\[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.6 Oracle 12c中的口令文件

在Oracle 12c中,由于许多新特性的引入,口令文件也发生了许多变化。可以从帮助说明中看到这些改变。在以下帮助中,可以看到较 Oracle 11g 增加的选项包括 asm、extended、sysbackup、sysdg 等。

-bash-4.1$ orapwd

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

asm=<y/n> dbuniquename=<dbname> extended=<y/n> sysbackup=<y/n> sysdg=<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),

--asm参数表示自12c开始,口令文件也可以存储在ASM存储中。

asm - indicates that the password to be stored in

Automatic Storage Management (ASM) disk group is an ASM password. (optional).

dbuniquename - unique database name used to identify database

password files residing in ASM diskgroup only.

Ignored when asm option is specified (optional),

--以下扩展部分,用于存储SYSBACKUP、SYSDB和SYSKM等系统权限

extended - use the extended format for SYSBACKUP, SYSDG, and

SYSKM support and for longer identifiers (optional),

sysbackup - create SYSBACKUP entry (optional and requires the the extended format),

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

sysdg - create SYSDG entry (optional and requires the extended format),

sysdgpwd - password for SYSDG will be prompted if not specified at command line.

当创建口令文件时,可以指定SYSBACKUP,SYSDG参数,此时会在口令文件中增加相应的条目:

bash-4.1$ orapwd file=orapwenmoz entries=5 extended=y sysbackup=y sysdg=y

Enter password for SYS:

Enter password for SYSBACKUP:

Enter password for SYSDG:

bash-4.1$ strings orapwenmoz

ORACLE Remote Password file

8A8F025737A9097A

SYSBACKUP

1FB154AF96200DE2

SYSDG

CF86024A3182B7AD

在Oracle 12c中,除了之前的SYSDBA、SYSOPER特殊管理权限之外,现在又随之增加了SYSASM、SYSBACKUP、SYSDG、SYSKM等权限。当对用户授予相应的权限后,口令文件中就会增加相应的条目:

SQL> grant sysbackup to enmo;

Grant succeeded.

SQL> select * from v$pwfile_users;

USERNAME SYSDB SYSOP SYSAS SYSBA SYSDG SYSKM CON_ID

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

SYS TRUE TRUE FALSE FALSE FALSE FALSE 0

ENMO FALSE FALSE FALSE TRUE FALSE FALSE 0

通过定义 ASM 参数,现在口令文件也可以被存储在 ASM 中,这样做的好处是,即可以通过ASM保护和加强口令文件的管理,在RAC模式下,更可以使得多实例共享同一个口令文件,保证口令文件的一致性。

通过类似如下的命令可以将口令文件创建到ASM磁盘组中:

orapwd file='+oradg/ENMO/orapwdenmo' dbuniquename='enmo' asm=y

创建完成之后,还需要通过配置指定数据库在启动时调用该口令文件:

srvctl modify database -db enmo -pwfile +oradg/ENMO/orapwdenmo

通过如下命令可以检查配置,经过配置的口令文件在通过crs启动数据库时会被调用生效:

srvctl config database -d enmo

在输出中包含了关于口令文件配置的信息:

Password file: +oradg/ENMO/orapwdenmo

经过12c的增强,Oracle终于将大到数据文件,小到参数文件和口令文件都纳入了数据库的统一管理和维护之中。

1.3.7 脚本的执行

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

@D:\Oracle\admin\eygle_nopt\scripts\CreateDB.sql

@D:\Oracle\admin\eygle_nopt\scripts\CreateDBFiles.sql

@D:\Oracle\admin\eygle_nopt\scripts\CreateDBCatalog.sql

@D:\Oracle\admin\eygle_nopt\scripts\emRepository.sql

@D:\Oracle\admin\eygle_nopt\scripts\lockAccount.sql

@D:\Oracle\admin\eygle_nopt\scripts\postDBCreation.sql

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

SET VERIFY OFF

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

set echo on

spool D:\Oracle\admin\eygle\scripts\CreateDB.log append

startup nomount pfile="D:\Oracle\admin\eygle\scripts\init.ora";

CREATE DATABASE "eygle"

MAXINSTANCES 8 MAXLOGHISTORY 1 MAXLOGFILES 16 MAXLOGMEMBERS 3 MAXDATAFILES 100

DATAFILE 'D:\Oracle\oradata\eygle\system01.dbf' SIZE 700M REUSE AUTOEXTEND ON NEXT 10240K MAXSIZE UNLIMITED

EXTENT MANAGEMENT LOCAL

SYSAUX DATAFILE 'D:\Oracle\oradata\eygle\sysaux01.dbf' SIZE 600M REUSE AUTOEXTEND ON NEXT 10240K MAXSIZE UNLIMITED

SMALLFILE DEFAULT TEMPORARY TABLESPACE TEMP TEMPFILE 'D:\Oracle\oradata\eygle\temp01.dbf' SIZE 20M REUSE AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED

SMALLFILE UNDO TABLESPACE "UNDOTBS1" DATAFILE 'D:\Oracle\oradata\eygle\undotbs01.dbf' SIZE 200M REUSE AUTOEXTEND ON NEXT 5120K MAXSIZE UNLIMITED

CHARACTER SET ZHS16GBK

NATIONAL CHARACTER SET AL16UTF16

LOGFILE GROUP 1 ('D:\Oracle\oradata\eygle\redo01.log') SIZE 51200K,

GROUP 2 ('D:\Oracle\oradata\eygle\redo02.log') SIZE 51200K,

GROUP 3 ('D:\Oracle\oradata\eygle\redo03.log') SIZE 51200K

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

spool off

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

(1)通过SYS连接;

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

(3)开始数据库创建。

注意:如果选择 OMF 方式管理文件,控制文件的名称在创建数据库之前是未知的,所以创建数据库之后才能得到名称加入参数文件中,一般这个文件会包含类似如下语句。

set linesize 2048;

column ctl_files NEW_VALUE ctl_files;

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

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

1.3.8 db_name参数和 instance_name参数

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

CREATE DATABASE "eygle"

这是数据库最重要的开始,其中“eygle”就是数据库名称。

对于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]$ export ORACLE_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

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

新的实例具有独立的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: database name 'EYGLE' in controlfile is not 'JULIA'

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

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> set block 2

BLOCK# 2

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

BBED> p kcvfh

struct kcvfh, 360 bytes @0

struct kcvfhbfh, 20 bytes @0

ub1 type_kcbh @0 0x0b

ub1 frmt_kcbh @1 0xa2

ub1 spare1_kcbh @2 0x00

ub1 spare2_kcbh @3 0x00

ub4 rdba_kcbh @4 0x00400001

ub4 bas_kcbh @8 0x00000000

ub2 wrp_kcbh @12 0x0000

ub1 seq_kcbh @14 0x01

ub1 flg_kcbh @15 0x04 (KCBHFCKV)

ub2 chkval_kcbh @16 0xa837

ub2 spare3_kcbh @18 0x0000

struct kcvfhhdr, 76 bytes @20

ub4 kccfhswv @20 0x00000000

ub4 kccfhcvn @24 0x0b200000

ub4 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

ub4 kccfhcsq @40 0x0000064a

ub4 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脚本,用于创建数据字典,这是非常重要的一个脚本,其中存储了数据字典的创建语句及注释说明,当我们对某些数据字典存在兴趣时,可以通过检查这个文件得到更为详细的信息。

在Oracle 11g之前,sql.bsq脚本包含了所有的SQL语句;自Oracle 11g开始,这个文件被拆分为多个.bsq文件,sql.bsq文件中描述了拆分后的文件调用:

rem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

rem Whenever new column is created to store internal, user or kernel column

rem number, be sure to update the structure adtDT in atb.c so that those

rem columns will be updated properly during drop column.

rem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

rem

dcore.bsq

dsqlddl.bsq

dmanage.bsq

dplsql.bsq

dtxnspc.bsq

dfmap.bsq

denv.bsq

drac.bsq

dsec.bsq

doptim.bsq

dobj.bsq

djava.bsq

dpart.bsq

drep.bsq

daw.bsq

dsummgt.bsq

dtools.bsq

dexttab.bsq

ddm.bsq

dlmnr.bsq

ddst.bsq

拆分后的基础SQL更加清晰,如dcore.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> startup nomount;

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 in opening 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文件中包含的数据库核心信息非常重要,在很多时候,这个文件可以帮助我们解答很多技术疑惑。

1.3.10 数据文件及字典的创建

再来看一看CreateDBFiles.sql文件:

SET VERIFY OFF

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

set echo on

spool D:\Oracle\admin\eygle\scripts\CreateDBFiles.log append

CREATE SMALLFILE TABLESPACE "USERS" LOGGING DATAFILE 'D:\Oracle\oradata\eygle\users01. dbf' SIZE 5M REUSE AUTOEXTEND ON NEXT 1280K MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO;

ALTER DATABASE DEFAULT TABLESPACE "USERS";

spool off

这个过程向数据库中创建了USERS表空间,并将该表空间设置为系统缺省的数据表空间,注意最后一句:

ALTER DATABASE DEFAULT TABLESPACE "USERS";

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

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脚本创建数据字典,catalog等脚本被依次调用,创建DBA_* 等一系列字典视图:

SET VERIFY OFF

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

set echo on

spool D:\Oracle\admin\eygle\scripts\CreateDBCatalog.log append

@D:\Oracle\11.2.0\rdbms\admin\catalog.sql;

@D:\Oracle\11.2.0\rdbms\admin\catblock.sql;

@D:\Oracle\11.2.0\rdbms\admin\catproc.sql;

@D:\Oracle\11.2.0\rdbms\admin\catoctk.sql;

@D:\Oracle\11.2.0\rdbms\admin\owminst.plb;

connect "SYSTEM"/"&&systemPassword"

@D:\Oracle\11.2.0\sqlplus\admin\pupbld.sql;

connect "SYSTEM"/"&&systemPassword"

set echo on

spool D:\Oracle\admin\eygle\scripts\sqlPlusHelp.log append

@D:\Oracle\11.2.0\sqlplus\admin\help\hlpbld.sql helpus.sql;

spool off

spool off

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

SET VERIFY OFF

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

set echo off

spool D:\Oracle\admin\eygle\scripts\emRepository.log append

@D:\Oracle\11.2.0\sysman\admin\emdrep\sql\emreposcre D:\Oracle\11.2.0 SYSMAN &&sysmanPassword TEMP ON;

WHENEVER SQLERROR CONTINUE;

spool off

接下来是用户管理脚本,lockAccount.sql用于锁定那些暂时用不到的缺省数据库用户,以后用户可以在需要时主动解锁,但是为了安全,Oracle现在需要锁定这些用户:

SET VERIFY OFF

set echo on

spool D:\Oracle\admin\eygle\scripts\lockAccount.log append

BEGIN

FOR item IN ( SELECT USERNAME FROM DBA_USERS WHERE ACCOUNT_STATUS IN ('OPEN', 'LOCKED',

'EXPIRED') AND USERNAME NOT IN ( 'SYS','SYSTEM') )

LOOP

dbms_output.put_line('Locking and Expiring: ' || item.USERNAME);

execute immediate 'alter user ' ||

sys.dbms_assert.enquote_name(

sys.dbms_assert.schema_name(

item.USERNAME),false) || ' password expire account lock' ;

END LOOP;

END;

/

spool off

注意:以上的SQL中,FOR循环锁定语句是非常常用的PL/SQL代码,建议DBA们能够熟练编写和使用。

postDBCreation.sql脚本用于完成数据库创建后的一些收尾工作,如创建SPFILE文件、配置EM资料库等:

SET VERIFY OFF

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

set echo on

spool D:\Oracle\admin\eygle\scripts\postDBCreation.log append

@D:\Oracle\11.2.0\rdbms\admin\catbundle.sql psu apply;

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;

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

set echo on

create spfile='D:\Oracle\11.2.0\database\spfileeygle.ora' FROM

pfile='D:\Oracle\admin\ eygle\scripts\init.ora';

shutdown immediate;

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

startup ;

host D:\Oracle\11.2.0\bin\emca.bat -config dbcontrol db -silent -DB_UNIQUE_NAME eygle -PORT 1521 -EM_HOME D:\Oracle\11.2.0 -LISTENER LISTENER -SERVICE_NAME eygle -SID eygle -ORACLE_HOME D:\Oracle\11.2.0 -HOST oracle-vm -LISTENER_OH D:\Oracle\11.2.0 -LOG_FILE D:\Oracle\admin\eygle\scripts\emConfig.log;

spool off

exit;

完成这些脚本,一个自定制的数据库就基本创建完成了。