天天看点

《循序渐进Oracle:数据库管理、优化与备份恢复》一一1.3 数据库创建的脚本

本节书摘来自异步社区出版社《循序渐进oracle:数据库管理、优化与备份恢复》一书中的第1章,第1.3节,作者:盖国强,更多章节内容可以访问云栖社区“异步社区”公众号查看。

循序渐进oracle:数据库管理、优化与备份恢复

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

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

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

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

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

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

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

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

(2)设置oracle_sid环境变量。

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

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

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

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

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

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

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

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

使用oradim工具后,会在$oracle_homedatabase目录下生成一个日志文件。

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

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

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

注意这里,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_homedatabase目录)。

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

spfile.ora→spfile.ora →init.ora。

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

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

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

接下来又可以启动另外oracle_home下oracle_sid为eygle的实例:

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

通过oracle提供的一个小工具sysresv,我们可以找到对应于不同的oracle_sid,操作系统上创建的共享内存段id(shared memory)和信号量id(semaphores)等信息。

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

该文件的主要内容如下:

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

与linux/unix上的情况类似,windows上的oracle环境也依赖于服务而存在,如图1-24所示。

《循序渐进Oracle:数据库管理、优化与备份恢复》一一1.3 数据库创建的脚本

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

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

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

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

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

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

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

作为oracle数据库的重要组成部分instance也存在一个参数标识:instance_name。

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

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

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

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

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

总结一下,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相关设置类似如下示例:

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

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

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

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

注意:

force参数是oracle 10g中增加的,ignorecase参数是11g新增加的。

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

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

[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身份登录数据库:

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

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

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

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

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

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

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

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

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

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

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

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

当remote_login_passwordfile=exclusive时:

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

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

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

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

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

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

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

(1)通过sys连接;

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

(3)开始数据库创建;

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

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

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

create database "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:

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

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

然后我们启动实例名称为julia的instance:

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

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

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

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

我们再来看一看如果参数文件中的db_name和控制文件中的db_name不一致会出现什么错误。

修改参数文件中的db_name参数:

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

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

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

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

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

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

提示:

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

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

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

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

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

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

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

再来看createdbfiles.sql文件:

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

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

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

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

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

emrepository.sql文件是用于创建em档案库的:

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

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

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

(2)解锁两个账号;

(3)编译;

(4)配置em。