Oracle 9i & 10g编程艺术-深入数据库体系结构——第3章:文件

第3章                      文件

这一章中,我们将分析构成数据库和实例的8种文件类型。与实例相关的文件只有:

q         参数文件(parameter file):这些文件告诉Oracle实例在哪里可以找到控制文件,并且指定某些初始化参数,这些参数定义了某种内存结构有多大等设置。我们还会介绍存储数据库参数文件的两种选择。

q         跟踪文件(trace file):这通常是一个服务器进程对某种异常错误条件做出响应时创建的诊断文件。

q         警告文件(alert file):与跟踪文件类似,但是包含“期望”事件的有关信息,并且通过一个集中式文件(其中包括多个数据库事件)警告DBA

q         构成数据库的文件包括:

q         数据文件(data file):这些文件是数据库的主要文件;其中包括数据表、索引和所有其他的段。

q         临时文件(temp file):这些文件用于完成基于磁盘的排序和临时存储。

q         控制文件(control file):这些文件能告诉你数据文件、临时文件和重做日志文件在哪里,还会指出与文件状态有关的其他元数据。

q         重做日志文件(redo log file):这些就是事务日志。

q         密码文件(password file):这些文件用于对通过网络完成管理活动的用户进行认证。我们不打算详细讨论这些文件。

Oracle 10g 开始,又增加了两种新的可选文件类型,可以帮助Oracle实现更快的备份和更快的恢复操作。这两类新文件是:

q         修改跟踪文件(change tracking file):这个文件有利于对Oracle数据建立真正的增量备份。修改跟踪文件不一定非得放在闪回恢复区(Flash Recovery Area),不过它只与数据库备份和恢复有关,所以我们将在介绍闪回恢复区时再讨论这个文件。

q         闪回日志文件(flashback log file):这些文件存储数据库块的“前映像”,以便完成新增加的FLASHBACK DATABASE命令。

我们还会讨论通常与数据库有关的其他类型的文件,如:

q         转储文件(dump file DMP file):这些文件由Export(导出)数据库实用程序生成,并由Import(导入)数据库实用程序使用。

q         数据泵文件(Data Pump file):这些文件由Oracle 10g 新增的数据泵导出(Data Pump Export)进程生成,并由数据泵导入(Data Pump Import)进程使用。外部表也可以创建和使用这种文件格式。

q         平面文件(flat file):这些无格式文件可以在文本编辑器中查看。通常会使用这些文件向数据库中加载数据。

以上文件中,最重要的是数据文件和重做日志文件,因为其中包含了你辛辛苦苦才积累起来的数据。只要有这两个文件,就算是其他文件都没有了,我也能得到我的数据。如果把重做日志文件弄丢失了,可能会丢失一些数据。如果把数据文件和所有备份都丢失了,那么这些数据就永远也找不回来了。

下面将分别介绍上述各类文件,并分析这些文件中会有哪些内容。

3.1   参数文件

Oracle数据库有关的参数文件有很多,从客户工作站上的tnsnames.ora文件(用于“查找”网络上的一个服务器)到服务器上的listener.ora文件(用于启动网络监听器),还有sqlnet.oracman.oraldap.ora等文件。不过,最重要的参数文件是数据库的参数文件,如果没有这个参数文件,甚至无法启动数据库。其他文件也很重要;它们涉及网络通信以及与数据库连接的各个方面。不过,这些参数文件超出了我们的范围,这里不做讨论。要了解如何配置和建立这些参数文件,建议你参考Net Services Administrator’s Guide。不过,作为开发人员,这些文件应该已经为你设置好了,不需要你来设置。

数据库的参数文件通常称为初始文件(init file),或init.ora文件。这是因为历史上它的默认名就是init<ORACLE_SID>.ora。之所以称之为“历史上”的默认名,原因是从Oracle9i Release 1以来,对于存储数据库的参数设置,引入了一个有很大改进的新方法:服务器参数文件(server parameter file),或简称为SPFILE。这个文件的默认名为spfile<ORACLE_SID>.ora。接下来分别介绍这两种参数文件。

注意    如果你还不熟悉术语SIDORACLE_SID,下面给出一个完整的定义。SID是站点标识符(site identifie)。在UNIX中,SIDORACLE_HOMEOracle软件的安装目录)一同进行散列运算,创建一个惟一的键名从而附加到SGA。如果ORACLE_SIDORACLE_HOME设置不当,就会得到ORACLE NOT AVAILABLE ORACLE不可用)错误,因为无法附加到这个惟一键所标识的共享内存段。在Windows上,使用共享内存的方式与UNIX中有所不同,不过,SID还是很重要。同一个ORACLE_HOME上可以有多个数据库,所以需要有办法惟一地标识各个数据库及相应的配置文件。

如果没有参数文件,就无法启动一个Oracle数据库。所以参数文件相当重要,到了Oracle9i Release 29.2及以上版本),备份和恢复工具——恢复管理器(Recovery ManagerRMAN)认识到了这个文件的重要性,允许把服务器参数文件包括在备份集中(而不是遗留的init.ora 参数文件类型)。不过,由于init.ora参数文件只是一个纯文本文件,可以用任何文本编辑器创建,所以这个文件不需要你花大力气去“保卫”。只要知道文件中的内容,完全可以重新创建(例如,如果你能访问数据库的警告日志,就可以从中获得参数文件的信息)。

下面依次介绍这两类参数文件(init.oraSPFILE),不过,在此之前,先来看看数据库参数文件是什么样子。

3.1.1             什么是参数?

简单地说,可以把数据库参数想成是一个“键”/“值”对。在上一章你已经看到过一个很重要的参数,即DB_NAME。这个DB_NAME参数简单地存储为db_name = ora 10g 。这里的“键”是DB_NAME,“值”是ora 10g ,这就是我们的键/值对。要得到一个实例参数的当前值,可以查询V$视图V$PARAMETER。另外,还可以在 SQL*Plus中使用SHOW PARAMETER命令来查看,如:

sys@ORA 10G > select value

2 from v$parameter

3 where name = 'pga_aggregate_target';

VALUE

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

1073741824

 

sys@ORA 10G > show parameter pga_agg

NAME                                            TYPE              VALUE

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

pga_aggregate_target               big integer     1G

无论采用哪种方法,输出的信息基本上都一样,不过从V$PARAMETER能得到更多信息(这个例子中只选择了一列,实际上还可以选择更多的列)。但是,我还是比较倾向于使用SHOW PARAMETER,因为这个命令使用更简单,而且它会自动完成“通配”。注意我只键入了pga_aggSHOW PARAMETER会自动在前面和后面添加%

注意    所有V$视图和所有字典视图在Oracle Database Reference手册中都有充分的说明。要想了解给定视图里有什么,这个手册可以作为一个权威资源。

对于Oracle 9.0.1 9.2.010.1.0版本,如果对可以设置的有记录的(documented)参数做一个统计,可能会分别得到参数个数为251258255(我相信,在不同的操作系统上可能还会增加另外的参数)。换句话说,参数个数(和参数名)因版本而异。大多数参数(如DB_BLOCK_SIZE)留存已久(它们不会因版本变化而消失),不过,随着时间的推移,其他的很多参数会随着实现的改变而过时。

例如,在Oracle 9.0.1 中有一个DISTRIBUTED_TRANSACTIONS参数,这个参数可以设置为某个正整数,它能控制数据库可以执行的并发分布式事务的个数。以前的版本中都有这个参数,但是在9.0.1以后,这个参数就被去掉了。实际上,如果在以后的版本中还想使用这个参数,将产生一个错误:

ops$tkyte@ORA 10G > alter system set distributed_transactions = 10;

alter system set distributed_transactions = 10

*

ERROR at line 1:

ORA-25138: DISTRIBUTED_TRANSACTIONS initialization parameter has been made

obsolete

如果你想查看这些参数,了解有哪些参数,以及各个参数能做什么,请参考Oracle Database Reference手册。这个手册的第1章就详细地分析了每一个有记录的参数。需要指出,一般来讲,这些参数的默认值对于大多数系统都已经足够了(如果某些参数是从其他参数得到默认设置,则完全可以使用所得到的值)。一般而言,要为各个数据库分别设置不同的参数值,如CONTROL_FILES参数(指定系统上控制文件的位置)、DB_BLOCK_SIZE(数据库块大小)以及与内存相关的各个参数。

注意,在上一段中我用了“有记录的”(documented)一词。还有一些无记录的(undocumented)参数。如果参数名用下划线(_)开头,就说明这个参数在文档中未做说明,即所谓的“无记录”。关于这些参数有很多推测。因为文档中没有这些参数,有些人以为它们肯定是“神奇的”,许多人都认为大家都知道这些参数,它们是Oracle“内部人士”用的。不过在我看来,实际上恰恰相反。这些参数并不是大家都知道的,而且也很少用到。其中大多数参数实际上令人厌烦,因为它们表示的只是过时的功能以及为保证向后兼容性而设置的标志。还有一些参数有助于数据的恢复,而不是数据库本身的恢复;例如,有些无记录的参数允许数据库在某些极端环境中启动,但是时间不长,只足以把数据取出来。取出数据后还是得重新构建。

除非Oracle Support明确要求,否则没有理由在你的配置中使用这种无记录的参数。其中很多参数都有副作用,而且可能是破坏性的。在我的开发数据库中,即使有无记录的参数,也只会设置一个这样的参数:

_TRACE_FILES_PUBLIC

有了这个参数,所有人都可以读取跟踪文件,而不仅限于DBA小组。在我的开发数据库上,我希望开发人员经常使用SQL_TRACETIMED_STATISTICSTKPROF实用程序(真的,我强烈建议使用它们);所以他们必须能读取跟踪文件。不过,由于Oracle 9.0.1 及以上版本增加了外部表,可以看到,即便是要允许别人访问跟踪文件,也不再需要使用这个参数了。

我的生产数据库则没有设置任何无记录的参数。实际上,前面提到的看似“安全”的无记录参数可能会在实际系统中产生不好的副作用。想想看跟踪文件中的敏感信息,如SQL甚至数据值(见后面的“跟踪文件”一节),问问自己,“我真的想让所有最终用户读取这个数据吗?”大多数情况下答案都是否定的。

警告    只有在Oracle Support要求的情况下才使用无记录的参数。使用这些参数可能对数据库有害,而且这些参数在不同版本中的实现可能有变化(而且将会改变)。

可以用两种方式来设置各个参数值:只设置当前实例的参数值,或者永久性地设置。你要确保参数文件包含你期望的值。使用遗留的init.ora参数文件时,这是一个手动过程。如果使用init.ora文件,要永久地修改一个参数值(即使服务器重启这个新设置也有效),就必须手动地编辑和修改init.ora参数文件。如果是服务器参数文件,则只需一条命令就能轻松完成,这多少有些全自动的味道。

3.1.2             遗留的init.ora参数文件

遗留的Oracle init.ora文件从结构来讲是一个相当简单的文件。这是一系列可变的键/值对。以下是一个init.ora文件示例:

db_name = "ora9ir2"

db_block_size = 8192

control_files = ("C:/oradata/control01.ctl", "C:/oradata/control02.ctl")

实际上,这与你在实际生活中可能遇到的最基本的init.ora文件很接近。如果块大小正是平台上的默认块大小(默认块大小随平台不同会有所不同),可以不要db_block_size参数。使用这个参数文件只是要得到数据库名和控制文件的位置。控制文件告诉Oracle其他的各个文件的位置,所以它们对于启动实例的“自启”过程(也称自举)非常重要。

既然已经知道了这些遗留的数据库参数文件是什么,也知道了在哪里能更详细地了解可设置的有效参数,最后还需要知道这些参数文件在磁盘上的什么位置。这个文件的命名约定默认为:

init$ORACLE_SID.ora      (Unix environment variable)

init%ORACLE_SID%.ora          (Windows environment variable)

而且,默认地把它放在以下目录中:

$ORACLE_HOME/dbs (Unix)

%ORACLE_HOME%/DATABASE (Windows)

有意思的是,许多情况下,你会发现这个参数文件中只有一行内容:

IFILE='C:/oracle/admin/ora 10g /pfile/init.ora'

IFILE指令与C中的#include很类似。它会在当前文件中包含指定文件的内容。前面的指令就会包含一个非默认位置上的init.ora文件。

需要注意,参数文件不必放在特定的位置上。启动一个实例时,可以在启动命令上使用pfile=filename选项。如果你想在数据库上尝试不同的init.ora参数,来看看不同设置带来的影响,这就非常有用。

遗留的参数文件可以利用任何纯文本编辑器来维护。例如,在UNIX/Linux上,我会用vi;在很多版本的Windows操作系统上,我会使用记事本;在大型机上,可能会使用Xedit。重要的是,你要全盘负责这个文件的编辑和维护。Oracle数据库本身没有命令可以用来维护init.ora文件中包含的值。例如,如果使用init.ora参数文件,发出ALTER SYSTEM命令来改变SGA组件的大小时,这并不会作为一个永久修改反映到init.ora文件中。如果希望这个修改是永久的,换句话说,如果希望这成为以后数据库重启时的默认值,你就要负责确保可能用于启动数据库的所有init.ora参数文件都得到手动地更新。

最后要注意,有意思的是,遗留的参数文件不一定位于数据库服务器上。之所以会引入存储参数(稍后将介绍),原因之一就是为了补救这种情况。试图启动数据库的客户机上必须有遗留的参数文件,这说明,如果你运行一台UNIX服务器,但是通过网络使用一台Windows台式机上安装的SQL*Plus来管理,这台计算机上就需要有数据库参数文件。

我还记得,发现参数文件没有存放在服务器上时我是多么的沮丧!那是几年前的事了,当时推出了一个全新的工具,名叫SQL*DBA。利用这个工具,可以完成远程操作(具体地讲,可以完成远程管理操作)。从我的服务器(那时运行的是SunOS),我能远程地连接一个大型机数据库服务器。而且我还能发出“关机”命令。不过,此时我意识到遇到了麻烦,启动实例时,SQL*DBA会“抱怨”无法找到参数文件。我发现这些参数文件(init.ora纯文本文件)放在客户机上,而不是在服务器上。SQL*DBA则是在启动大型机数据库的本地系统上查找参数。我不仅没有这样一个文件,也不知道要在这个文件中放什么内容才能让系统再次启动!我不知道db_name或控制文件位置(光是得到这些大型机文件的正确的命名约定都很困难),而且我无法访问大型机系统本身的日志。从那以后,我再也没有犯过同样的错误;这个教训实在太惨痛了。

DBA认识到init.ora参数文件必须放在启动数据库的客户机上时,这会导致这些参数文件大面积“繁殖”。每个DBA都想从自己的桌面运行管理工具,所以每个DBA都需要在自己的台式机上留有参数文件的一个副本。Oracle企业管理器(Oracle Enterprise ManagerOEM)之类的工具还会再增加一个参数文件,这会使情况更加混乱。这些工具试图将所有数据库的管理都集中到一台机器上,有时称之为“管理服务器”(management server)。这台机器会运行一个软件,所有DBA均使用这个软件来启动、关闭、备份和管理数据库。听上去是一个很不错的解决方案:把所有参数文件都集中在一个位置上,并使用GUI工具来完成所有操作。但事实是,完成某个管理任务时,有时直接从数据库服务器主机上的SQL*Plus发出启动命令会方便得多,这样又会有多个参数文件:一个参数文件在管理服务器上,另一个参数文件在数据库服务器上。而且这些参数文件彼此不同步,人们可能会奇怪,为什么他们上个月做的参数修改“不见了”,不过这些修改有可能会随机地再次出现。

所以引入了服务器参数文件(server parameter fileSPFILE),如今这可以作为得到数据库参数设置的惟一“信息来源”。

3.1.3             服务器参数文件

在访问和维护实例参数设置方面,SPFILEOracle做出的一个重要改变。有了SPFILE,可以消除传统参数文件存在的两个严重问题:

q         可以杜绝参数文件的繁殖。SPFILE总是存储在数据库服务器上;必须存在于服务器主机本身,不能放在客户机上。对参数设置来说,这样就可以只有一个“信息来源”。

q         无需在数据库之外使用文本编辑器手动地维护参数文件(实际上,更确切的说法是不能手动地维护)。利用ALTER SYSTEM 命令,完全可以直接将值写入SPFILE。管理员不必再手动地查找和维护所有参数文件。

这个文件的命名约定默认为:

spfile$ORACLE_SID.ora (Unix environment variable)

spfile%ORACLE_SID%.ora (Windows environment variable)

我强烈建议使用默认位置;否则会影响SPFILE的简单性。如果SPFILE在其默认位置,几乎一切都会为你做好。如果将SPFILE移到一个非默认的位置,你就必须告诉 Oracle到哪里去找SPFILE,这又会导致遗留参数文件的一大堆问题卷土重来!

1.      转换为SPFILE

假设有一个数据库,它使用了前面所述的遗留参数文件。转换为SPFILE非常简单;这里使用了CREATE SPFILE命令。

注意    还可以使用一个“逆”命令从SPFILE创建参数文件(parameter filePFILE),稍后我们会解释为什么希望这样做。

所以,假设使用一个init.ora参数文件,而且这个init.ora 参数文件确实在服务器的默认位置上,那么只需发出CREATE SPFILE命令,并重启服务器实例就行了:

sys@ORA 10G > show parameter spfile;

 

NAME                                        TYPE           VALUE

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

spfile                                          string

sys@ORA 10G > create spfile from pfile;

File created.

 

sys@ORA 10G > startup force;

ORACLE instance started.

 

Total System Global Area 603979776 bytes

Fixed Size 780300 bytes

Variable Size 166729716 bytes

Database Buffers 436207616 bytes

Redo Buffers 262144 bytes

Database mounted.

Database opened.

sys@ORA 10G > show parameter spfile;

 

NAME                                        TYPE           VALUE

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

spfile                                          string           /home/ora 10g /dbs/spfileora 10g .ora

这里使用SHOW PARAMETER命令显示出原先没有使用SPFILE,但是创建SPFILE并重启实例后,确实使用了这个SPFILE,而且它采用了默认名。

注意    在集群环境中,通过使用Oracle RAC,所有实例共享同一个SPFILE,所以要以一种受控的方式完成这个转换过程(从PFILE转换为SPFILE)。这个SPFILE可以包含所有参数设置,甚至各个实例特有的设置都可以放在这一个SPFILE中 ,但是必须把所有必须的参数文件合并为一个有以下格式的PFILE

在集群环境中,为了从使用各个PFILE转换为所有实例都共享一个公共的SPFILE,需要把各个PFILE合并为如下一个文件:

*.cluster_database_instances=2

*.cluster_database=TRUE

*.cluster_interconnects=' 10.10.10 .0'

*.compatible=' 10.1.0 .2.0'

*.control_files='/ocfs/O 10G /control01.ctl','/ocfs/O 10G /control02.ctl'

*.db_name='O 10G '

...

*.processes=150

*.undo_management='AUTO'

O 10G 1.instance_number=1

O 10G 2.instance_number=2

O 10G 1.local_listener='LISTENER_O 10G 1'

O 10G 2.local_listener='LISTENER_O 10G 2'

O 10G 1.remote_listener='LISTENER_O 10G 2'

O 10G 2.remote_listener='LISTENER_O 10G 1'

O 10G 1.thread=1

O 10G 2.thread=2

O 10G 1.undo_tablespace='UNDOTBS1'

O 10G 2.undo_tablespace='UNDOTBS2'

也就是说,集群中所有实例共享的参数设置都以*.开头。单个实例特有的参数设置(如INSTANCE_NUMBER和所用的重做THREAD)都以实例名(Oracle SID)为前缀。在前面的例子中,

q         PFILE对应包含两个节点的集群,其中的实例分别为O 10G 1O 10G 2

q         *.db_name = 'O 10G '这个赋值指示,使用这个SPFILE的所有实例会装载一个名为O 10G 的数据库。

q         O 10G 1.undo_tablespace='UNDOTBS1'指示,名为O 10G 1的实例会使用这个特定的撤销(undo)表空间,等等。

2.      设置SPFILE中的参数值

一旦根据SPFILE启动并运行数据库,下一个问题就是如何设置和修改其中的值。要记住,SPFILE是二进制文件,它们可不能用文本编辑器来编辑。这个问题的答案就是使用ALTER SYSTEM命令,语法如下(< > 中的部分是可选的,其中的管道符号(|)表示“取候选列表中的一个选项”):

Alter system set parameter=value <comment='text'> <deferred>

                           <scope=memory|spfile|both> <sid='sid|*'>

默认情况下,ALTER SYSTEM SET命令会更新当前运行的实例,并且会为你修改SPFILE,这就大大简化了管理;原先使用init.ora参数文件时,通过ALTER SYSTEM命令设置参数后,如果忘记更新init.ora参数文件,或者把init.ora参数文件丢失了,就会产生问题,使用SPFILE则会消除这些问题。

记住这一点,下面来详细分析这个命令中的各个元素:

q         parameter=value这个赋值提供了参数名以及参数的新值。例如,pga_aggregate_target = 1024m 会把PGA_AGGREGATE_TARGET参数值设置为1,024 MB1 GB)。

q         comment='text'是一个与此参数设置相关的可选注释。这个注释会出现在V$PARAMETER视图的UPDATE_COMMENT字段中。如果使用了相应选项允许同时保存对SPFILE的修改,注释会写入SPFILE,而且即便服务器重启也依然保留,所以将来重启数据库时会看到这个注释。

q         deferred指定系统修改是否只对以后的会话生效(对当前建立的会话无效,包括执行此修改的会话)。默认情况下,ALTER SYSTEM命令会立即生效,但是有些参数不能“立即”修改,只能为新建立的会话修改这些参数。可以使用以下查询来看看哪些参数要求必须使用deferred

ops$tkyte@ORA 10G > select name

2 from v$parameter

3 where ISSYS_MODIFIABLE = 'DEFERRED';

 

NAME

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

backup_tape_io_slaves

audit_file_dest

object_cache_optimal_size

object_cache_max_size_percent

sort_area_size

sort_area_retained_size

olap_page_pool_size

 

7 rows selected.

上面的代码表明,SORT_AREA_SIZE可以在系统级修改,但是必须以延迟方式修改。以下代码显示了有deferred选项和没有deferred选项时修改这个参数的值会有什么结果:

ops$tkyte@ORA 10G > alter system set sort_area_size = 65536;

alter system set sort_area_size = 65536

*

ERROR at line 1:

ORA-02096: specified initialization parameter is not modifiable with this

option

 

ops$tkyte@ORA 10G > alter system set sort_area_size = 65536 deferred;

System altered.

q         SCOPE=MEMORY|SPFILE|BOTH指示了这个参数设置的“作用域”。设置参数值时作用域有以下选择:

§           SCOPE=MEMORY只在实例中修改;数据库重启后将不再保存。下一次重启数据库时,设置还是修改前的样子。

§           SCOPE=SPFILE只修改SPFILE中的值。数据库重启并再次处理SPFILE之前,这个修改不会生效。有些参数只能使用这个选项来修改,例如,processes参数就必须使用SCOPE=SPFILE,因为我们无法修改活动实例的processes值。

§           SCOPE=BOTH是指,内存和SPFILE中都会完成参数修改。这个修改将反映在当前实例中,下一次重启时,这个修改也会生效。这是使用SPFILE时默认的作用域值。如果使用init.ora参数文件,默认值则为SCOPE=MEMORY,这也是此时惟一合法的值。

q         sid='sid|*'主要用于集群环境;默认值为sid='*'。这样可以为集群中任何给定的实例惟一地指定参数设置。除非你使用Oracle RAC,否则一般不需要指定sid=设置。

这个命令的典型用法很简单:

ops$tkyte@ORA 10G > alter system set pga_aggregate_target= 1024m ;

System altered.

或者,更好的做法是,还可以指定COMMENT=赋值来说明何时以及为什么执行某个修改:

ops$tkyte@ORA 10G > alter system set pga_aggregate_target= 1024m

2 comment = 'changed 01-jan-2005 as per recommendation of George';

 

System altered.

 

ops$tkyte@ORA 10G > select value, update_comment

2 from v$parameter

3 where name = 'pga_aggregate_target';

 

VALUE

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

UPDATE_COMMENT

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

1073741824

changed 01-jan-2005 as per recommendation of George

3.      取消SPFILE中的值设置

下一个问题又来了,“好吧,这样就设置了一个值,但是现在我们又想‘取消这个设置’,换句话说,我们根本不希望SPFILE有这个参数设置,想把它删掉。但是既然不能使用文本编辑器来编辑这个文件,那我们该怎么办呢?”同样地,这也要通过ALTER SYSTEM命令来完成,但是要使用RESET子句:

Alter system reset parameter <scope=memory|spfile|both> sid='sid|*'

在这里,SCOPE/SID 设置的含义与前面一样,但是SID=部分不再是可选的。Oracle SQL Reference手册在介绍这个命令时有点误导,因为从手册来看,好像这只对RAC(集群)数据库有效。实际上,手册中有下面的说明:

alter_system_reset_clauseALTER SYSTEM命令的RESET子句)用于“真正应用集群”(RAC)环境。

接下来,它又说:

在非RAC环境中,可以为这个子句指定SID='*'

这就有点让人糊涂了。不过,要从SPFILE“删除”参数设置,也就是仍然采用参数原来的默认值,就要使用这个命令。所以,举例来说,如果我们想删除SORT_AREA_SIZE,以允许使用此前指定的默认值,可以这样做:

sys@ORA 10G > alter system reset sort_area_size scope=spfile sid='*';

System altered.

这样会从SPFILE中删除SORT_AREA_SIZE,通过执行以下命令可以验证这一点:

sys@ORA 10G > create pfile='/tmp/pfile.tst' from spfile;

File created.

然后可以查看/tmp/pfile.tst的内容,这个文件将在数据库服务器上生成。可以看到,参数文件中不再有SORT_AREA_SIZE参数了。

4.      SPFILE创建PFILE

上一节用到的CREATE PFILE...FROM SPFILE命令刚好与CREATE SPFILE相反。这个命令根据二进制SPFILE创建一个纯文本文件,生成的这个文件可以在任何文本编辑器中编辑,并且以后可以用来启动数据库。正常情况下,使用这个命令至少有两个原因:

q         创建一个“一次性的”参数文件,用于启动数据库来完成维护,其中有一些特殊的设置。所以,可以执行CREATE PFILE...FROM SPFILE命令,并编辑得到的文本PFILE,修改所需的设置。然后启动数据库,使用PFILE=<FILENAME>选项指定要使用这个PFILE而不是SPFILE。完成后,可以正常地启动,数据库又会使用SPFILE

q         维护修改历史,在注释中记录修改。过去,许多DBA会在参数文件中加大量的注释,来记录修改历史。例如,如果一年内把缓冲区缓存大小修改过20次,在db_cache_size init.ora参数设置前就会有20条注释,这些注释会指出修改的日期,以及修改的原因。SPFILE不支持这样做,但是如果习惯了以下用法,也可以达到同样的效果:

sys@ORA 10G > create pfile='init_01_jan_2005_ora 10g .ora' from spfile;

File created.

 

sys@ORA 10G > !ls -l $ORACLE_HOME/dbs/init_*

-rw-rw-r-- 1 ora 10g ora 10g 871 Jan 1 17:04 init_01_jan_2005_ora 10g .ora

sys@ORA 10G > alter system set pga_aggregate_target= 1024m

2 comment = 'changed 01-jan-2005 as per recommendation of George';

通过这种方式,修改历史就会在一系列参数文件中长久保存。

5.      修正被破坏的SPFILE

关于SPFILE还有最后一个问题,“SPFILE是二进制文件,如果SPFILE被破坏了,数据库无法启动,那该怎么办?还是init.ora文件更好一些,至少它是文本文件,我们可以直接编辑和修正”。嗯,这么说吧,SPFILE不会像数据文件、重做日志文件、控制文件等那样被破坏,但是,倘若真的发生了这种情况,还是有几种选择的。

首先,SPFILE中的二进制数据量很小。如果在UNIX平台上,只需一个简单的strings命令就能提取出所有设置:

[tkyte@localhost dbs]$ strings spfile$ORACLE_SID.ora

*.compatible=' 10.1.0 .2.0'

*.control_files='/home/ora 10g /oradata/ora 10g /control01.ctl','/home/ora 10g /oradata/or

a 10g /control02.ctl','/home/ora 10g /oradata/ora 10g /control03.ctl'

...

*.user_dump_dest='/home/ora 10g /admin/ora 10g /udump'

Windows上,则要用write.exeWordPad,即写字板)打开这个文件。WordPad会显示出文件中的所有文本,只需将其剪切并粘贴到init<ORACLE_SID>.ora中,就能创建启动实例的PFILE

万一SPFILE丢失了(不论是什么原因,反正我没有见过SPFILE消失的情况),还可以从数据库的警告日志恢复参数文件的信息(稍后将介绍警告日志的更多内容)。每次启动数据库时,警告日志都会包含如下一部分内容:

System parameters with non-default values:

processes = 150

timed_statistics = TRUE

shared_pool_size = 67108864

large_pool_size = 8388608

java_pool_size = 33554432

control_files = C:/oracle/oradata/ora9ir2w/CONTROL01.CTL,

C:/oracle/oradata/ora9ir2w/CONTROL02.CTL,

C:/oracle/oradata/ora9ir2w/CONTROL03.CTL

....

pga_aggregate_target = 25165824

aq_tm_processes = 1

PMON started with pid=2

DBW0 started with pid=3

通过这一部分内容,可以很容易地创建一个PFILE,再用CREATE SPFILE命令将其转换为一个新的SPFILE

3.1.4             参数文件小结

在这一节中,我介绍了管理Oracle初始化参数和参数文件的所有基础知识。我们了解了如何设置参数、查看参数值,以及如何让这些设置在数据库重启时依然保留。我们分析了两类数据库参数文件:传统的PFILE(简单的文本文件)和SPFILE(服务器参数文件)。对于所有现有的数据库,都推荐使用SPFILE,因为这更易于管理,而且也更为简洁。由于数据库的参数只有一个“信息来源”,而且可以使用ALTER SYSTEM命令持久地保存参数值,这使得SPFILE相当引人注目。自从有了SPFILE,我就一直在使用SPFILE,而且从来没有想过再回头去使用PFILE

3.2   跟踪文件

跟踪文件(Trace file)能提供调试信息。服务器遇到问题时,它会生成一个包含大量诊断信息的跟踪文件。如果开发人员设置了SQL_TRACE=TRUE,服务器就会生成一个包含性能相关信息的跟踪文件。我们之所以可以使用这些跟踪文件,是因为Oracle是一个允许充分测量的软件。我所说的“可测量”(instrumented)是指,编写数据库内核的程序员在内核中放入了调试代码,而且调试代码相当多。这些调试代码仍然被程序员有意留在内核中。

我见过许多开发人员都认为调试代码会带来开销,认为系统投入生产阶段之前必须把这些调试代码去掉,希望从代码中“挤出”点滴的性能。当然,随后他们可能又会发现代码中有一个“bug”,或者“运行得没有应有的那么快”(最终用户也把这称为“bug”。对于最终用户来说,性能差就是bug!)。此时,他们多么希望调试代码还在原处未被删掉(或者,如果原来没有加过调试代码,他们可能很后悔当初为什么没有添加)。特别是,他们无法再向生产系统中添加调试代码,在生产环境中,新代码必须先经过测试,这可不是说添加就添加那么轻松。

Oracle数据库(以及应用服务器和Oracle应用)都是可以充分测量的。数据库中这种测量性反映在以下几方面:

q         V$视图:大多数V$视图都包含“调试”信息。V$WAITSTATV$SESSION_EVENT还有其他许多V$视图之所以存在,就是为了让我们知道内核内部到底发生了什么。

q         审计命令:利用这个命令,你能指定数据库要记录哪些事件以便日后分析。

q         资源管理器(DBMS_RESOURCE_MANAGER):这个特性允许你对数据库中的资源(CPUI/O等)实现微管理。正是因为数据库能访问描述资源使用情况的所有运行时统计信息,所以才可能有资源管理器。

q         Oracle“事件”:基于Oracle事件,能让Oracle生成所需的跟踪或诊断信息。

q         DBMS_TRACE:这是PL/SQL引擎中的一个工具,它会全面地记录存储过程的调用树、所产生的异常,以及遇到的错误。

q         数据库事件触发器:这些触发器(如ON SERVERERROR)允许你监控和记录你觉得“意外”或非正常的情况。例如,可以记录发生“临时空间用尽”错误时正在运行的SQL

q         SQL_TRACE:这个SQL跟踪工具还可以采用一种扩展方式使用,即通过10046 Oracle事件。

还不止这些。在应用设计和开发中,测量至关重要,每一版Oracle数据库的测量性都越来越好。实际上,Oracle9i Release 2 Oracle 10g Release 1这两个版本之间增加的测量代码量就相当显著。Oracle 10g 将内核中的代码测量发展到一个全新的层次。

在这一节中,我们将重点讨论各种跟踪文件中的信息。这里会分析有哪些跟踪文件,这些跟踪文件存放在哪里,以及对这些跟踪文件能做些什么。

通常有两类跟踪文件,对这两类跟踪文件的处理完全不同:

q         你想要的跟踪文件:例如,启用SQL_TRACE=TRUE选项的结果,其中包含有关会话的诊断信息,有助于你调整应用,优化应用的性能,并诊断出遭遇的瓶颈。

q         你不想要的跟踪文件,但是由于出现了以下错误,服务器会自动生成这些跟踪文件。这些错误包括ORA-00600“Internal Error”(内部错误)、ORA-03113“End of file on communication channel”(通信通道上文件结束)或ORA-07445“Exception Encountered”(遇到异常)。这些跟踪文件包含一些诊断信息,它们主要对Oracle Support的分析人员有用,但对我们来说,除了能看出应用中哪里出现了内部错误之外,用处不大。

3.2.1             请求的跟踪文件

你想要的跟踪文件通常都是因为设置了SQL_TRACE=TRUE生成的结果,或者是通过10046事件使用扩展的跟踪工具生成的,如下所示:

ops$tkyte@ORA 10G > alter session set events

2 '10046 trace name context forever, level 12';

Session altered.

1.      文件位置

不论是使用SQL_TRACE还是扩展的跟踪工具,Oracle都会在数据库服务器主机的以下两个位置生成一个跟踪文件:

q         如果使用专用服务器连接,会在USER_DUMP_DEST参数指定的目录中生成跟踪文件。

q         如果使用共享服务器连接,则在BACKGROUND_DUMP_DEST参数指定的目录中生成跟踪文件。

要想知道跟踪文件放在哪里,可以从SQL*Plus执行SHOW PARAMETER DUMP_DEST命令来查看,也可以直接查询V$PARAMETER视图:

ops$tkyte@ORA 10G > select name, value

2 from v$parameter

3 where name like '%dump_dest%'

4 /

 

NAME                                         VALUE

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

background_dump_dest         /home/ora 10g /admin/ora 10g /bdump

user_dump_dest                      /home/ora 10g /admin/ora 10g /udump

core_dump_dest                      /home/ora 10g /admin/ora 10g /cdump

这里显示了3个转储(跟踪)目标。后台转储(background dump)目标由所有“服务器”进程使用(第5章会全面介绍Oracle后台进程及其作用)。

如果使用Oracle的共享服务器连接,就会使用一个后台进程;因此,跟踪文件的位置由BACKGROUND_DUMP_DEST确定。如果使用的是专用服务器连接,则会使用一个用户或前台进程与Oracle交互;所以跟踪文件会放在USER_DUMP_DEST参数指定的目录中。如果出现严重的Oracle内部错误(如UNIX上的“segmentation fault”错误),或者如果Oracle Support要求你生成一个跟踪文件来得到额外的调试信息,CORE_DUMP_DEST参数则定义了此时这个“内核”文件应该放在哪里。一般而言,我们只对后台和用户转储目标感兴趣。需要说明,除非特别指出,这本书里都使用专用服务器连接。

如果你无法访问V$PARAMETER视图,那么可以使用DBMS_UTILITY来访问大多数(但不是全部)参数的值。从下面的例子可以看出,要看到这个信息(还不止这些),只需要CREATE SESSION权限:

ops$tkyte@ORA 10G > create user least_privs identified by least_privs;

User created.

 

ops$tkyte@ORA 10G > grant create session to least_privs;

Grant succeeded.

 

ops$tkyte@ORA 10G > connect least_privs/least_privs

Connected.

least_privs@ORA 10G > declare

2          l_string varchar2(255);

3          l_dummy number;

4 begin

5          l_dummy := dbms_utility.get_parameter_value

6          ( 'background_dump_dest', l_dummy, l_string );

7          dbms_output.put_line( 'background: ' || l_string );

8          l_dummy := dbms_utility.get_parameter_value

9          ( 'user_dump_dest', l_dummy, l_string );

10       dbms_output.put_line( 'user: ' || l_string );

11 end;

12 /

background: /home/ora 10g /admin/ora 10g /bdump

user: /home/ora 10g /admin/ora 10g /udump

 

PL/SQL procedure successfully completed.

2.      命名约定

Oracle中跟踪文件的命名约定总在变化,不过,如果把你的系统上的跟踪文件名作为示例,应该能很容易地看出这些命名有一个模板。例如,在我的各台服务器上,跟踪文件名如表3-1所示。

3-1 跟踪文件名示例

跟踪文件名                                                                 数据库版本

ora 10g _ora_24574.trc                                   Linux                                          10g Release 1

ora9ir2_ora_24628.trc                                   Linux                                          9i Release 2

ora_10583.trc                                                   Linux                                          9i Release 1

ora9ir2w_ora_688.trc                                     Windows                                   9i Release 2

ora 10g _ora_1256.trc                                      Windows                                   10g Release 1

在我的服务器上,跟踪文件名可以分为以下几部分:

q         文件名的第一部分是ORACLE_SID(但Oracle9i Release 1例外,在这一版本中,Oracle决定去掉这一部分)。

q         文件名的下一部分只有一个ora

q         跟踪文件名中的数字是专用服务器的进程ID, 可以从V$PROCESS视图得到。

q         因此,在实际中(假设使用专用服务器模式),需要访问4个视图:

q         V$PARAMETER:找到USER_DUMP_DEST指定的跟踪文件位置。

q         V$PROCESS:查找进程ID

q         V$SESSION:正确地标识其他视图中的会话信息。

q         V$INSTANCE:得到ORACLE_SID

前面提到过,可以使用DBMS_UTILITY来找到位置,而且通常你“知道”ORACLE_SID,所以从理论上讲只需要访问V$SESSIONV$PROCESS,但是,为了便于使用,这4个视图你可能都想访问。

以下查询可以生成跟踪文件名:

ops$tkyte@ORA 10G > alter session set sql_trace=true;

Session altered.

ops$tkyte@ORA 10G > select c.value || '/' || d.instance_name ||

2 '_ora_' || a.spid || '.trc' trace

3 from v$process a, v$session b, v$parameter c, v$instance d

4 where a.addr = b.paddr

5 and b.audsid = userenv('sessionid')

6 and c.name = 'user_dump_dest'

7 /

TRACE

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

/home/ora 10g /admin/ora 10g /udump/ora 10g _ora_24667.trc

 

ops$tkyte@ORA 10G >

显然,在Windows平台上要把 / 换成 /。如果使用9i Release 1,只需发出以下查询,不用在跟踪文件名中增加实例名:

select c.value || 'ora_' || a.spid || '.trc'

3.      对跟踪文件加标记

有一种办法可以对跟踪文件“加标记”,这样即使你无权访问V$PROCESSV$SESSION,也能找到跟踪文件。假设你能读取USER_DUMP_DEST目录,就可以使用会话参数TRACEFILE_IDENTIFIER。采用这种方法,可以为跟踪文件名增加一个可以惟一标识的串,例如:

ops$tkyte@ORA 10G > alter session set tracefile_identifier = 'Look_For_Me';

Session altered.

 

ops$tkyte@ORA 10G > alter session set sql_trace=true;

Session altered.

 

ops$tkyte@ORA 10G > !ls /home/ora 10g /admin/ora 10g /udump/*Look_For_Me*

/home/ora 10g /admin/ora 10g /udump/ora 10g _ora_24676_Look_For_Me.trc

 

ops$tkyte@ORA 10G >

可以看到,跟踪文件还是采用标准的<ORACLE_SID>_ora_<PROCESS_ID>格式命名,但是这里还有我们为它指定的一个惟一的串,这样就能很容易地找到“我们的”跟踪文件名。

3.2.2             针对内部错误生成的跟踪文件

这一节最后我再来谈谈另一类跟踪文件,这些跟踪文件不是我们想要的,只是由于ORA-00600或另外某个内部错误而自动生成。对这些跟踪文件我们能做些什么吗?

答案很简单,一般来讲,这些跟踪文件不是给你我用的。它们只对Oracle Support有用。不过,我们向Oracle Support提交iTAR时,这些跟踪文件会很有用。有一点很重要:如果得到内部错误,修改这个错误的惟一办法就是提交一个iTAR。如果你只是将错误忽略,除非出现意外,否则它们不会自行修正。

例如,在Oracle 10g Release 1中,如果创建下表,并运行以下查询,就会得到一个内部错误(也可能不会得到错误,因为这个错误已经作为一个bug提交,并在后来的补丁版本中得到修正):

ops$tkyte@ORA 10G > create table t ( x int primary key );

Table created.

 

ops$tkyte@ORA 10G > insert into t values ( 1 );

1 row created.

 

ops$tkyte@ORA 10G > exec dbms_stats.gather_table_stats( user, 'T' );

PL/SQL procedure successfully completed.

 

ops$tkyte@ORA 10G > select count(x) over ()

2 from t;

from t

*

ERROR at line 2:

ORA-00600: internal error code, arguments: [12410], [], [], [], [], [], [], []

如果你是一名DBA,会发现用户转储目标中突然冒出这个跟踪文件。 或者,如果你是一名开发人员,你的应用将产生一个ORA-00600错误,你肯定想知道到底发生了什么。跟踪文件中信息很多(实际上,另外还有35,000行),但一般来讲,这些信息对你我来说都没有用。我们只是想压缩这个跟踪文件,并将其上传来完成iTAR处理。

不过,确实有些信息能帮助你跟踪到“谁”造成了错误,错误是“什么”,以及错误在“哪里”,另外,利用http://metalink.oracle.com,你还能发现这些问题是不是别人已经遇到过(许多次),以及为什么会出现这些错误。快速检查一下跟踪文件的最前面,你会得到一些有用的信息,如:

Dump file c:/oracle/admin/ora 10g /udump/ora 10g _ora_1256.trc

Sun Jan 02 14:21:29 2005

ORACLE V 10.1.0 .3.0 - Production vsnsta=0

vsnsql=13 vsnxtr=3

Oracle Database 10g Enterprise Edition Release 10.1.0 .3.0 - Production

With the Partitioning, OLAP and Data Mining options

Windows XP Version V5.1 Service Pack 2

CPU :                           1 - type 586

Process Affinity:         0x00000000

Memory (A/P) :           PH: 11M / 255M , PG: 295M / 1002M , VA: 1605M / 2047M

Instance name:          ora 10g

Redo thread mounted by this instance:    1

Oracle process number: 21

Windows thread id: 1256, image:     ORACLE.EXE (SHAD)

你在http://metalink.oracle.com上提交iTAR时,数据库信息当然很重要,不仅如此,如果在http://metalink.oracle.com上查看是否以前已经提出过这个问题,这些数据库信息也很有用。另外,可以看出错误出现在哪个Oracle实例上。并发地运行多个实例是很常见的,所以把问题隔离到一个实例上会很有用。

*** 2005-01-02 14:21:29.062

*** ACTION NAME:() 2005-01-02 14:21:28.999

*** MODULE NAME:(SQL*Plus) 2005-01-02 14:21:28.999

*** SERVICE NAME:(SYS$USERS) 2005-01-02 14:21:28.999

跟踪文件中的这一部分是Oracle 10g 新增的,Oracle9i里没有。它显示了V$SESSIONACTIONMODULE列中的会话信息。这里可以看到,是一个SQL*Plus会话导致了错误(开发人员应该设置ACTIONMODULE信息;有些环境已经为你做了这项工作,如Oracle FormsHTML DB)。

另外还可以得到SERVICE NAME。这就是连接数据库所用的服务名(这里就是SYS$USERS),由此看出没有通过TNS服务来连接。如果使用user/pass@ora 10g .localdomain登录,可以看到:

*** SERVICE NAME:(ora 10g ) 2005-01-02 15:15:59.041

其中ora 10g 是服务名(而不是TNS连接串;这是所连接TNS监听器中注册的最终服务)。这对于跟踪哪个进程/模块受此错误影响很有用。

最后,在查看具体的错误之前,可以看到会话ID和相关的日期/时间等进一步的标识信息(所有版本都提供了这些信息):

*** SESSION ID:(146.2) 2005-01-02 14:21:28.999

现在可以深入到内部看看错误本身了:

ksedmp: internal or fatal error

ORA-00600: internal error code, arguments: [12410], [], [], [], [], [], [], []

Current SQL statement for this session:

select count(x) over ()

         from t

----- Call Stack Trace -----

_ksedmp+524

_ksfdmp.160+14

_kgeriv+139

_kgesiv+78

_ksesic0+59

_qerixAllocate+4155

_qknRwsAllocateTree+281

_qknRwsAllocateTree+252

_qknRwsAllocateTree+252

_qknRwsAllocateTree+252

_qknDoRwsAllocate+9

...

这里也有一些重要的信息。首先,可以看到产生内部错误时正在执行的SQL语句,这有助于跟踪哪个(哪些)应用会受到影响。同时,由于这里能看到SQL,所以可以研究采用哪些“迂回路线”,用不同的方法编写SQL,看看能不能很快绕过问题解决bug。另外,也可以把出问题的SQL剪切并粘贴到SQL*Plus中,看看能不能为Oracle Support提供一个可再生的测试用例(当然,这些是最棒的测试用例)。

另一个重要信息是错误码(通常是60031137445)以及与错误码相关的其他参数。使用这些信息,再加上一些栈跟踪信息(显示按顺序调用的一组Oracle内部子例程),可能会发现这个bug已经报告过(还能找到解决方法、补丁等)。例如,使用以下查询串:

ora-00600 12410 ksesic0 qerixAllocate qknRwsAllocateTree

利用MetaLink的高级搜索(全文搜索bug数据库),很快就能发现bug 3800614, ORA-600 [12410] ON SIMPLE QUERY WITH ANALYTIC FUNCTION”。如果访问http://metalink.oracle.com,并使用这个文本进行搜索,可以找到这个bug,了解到下一版中已经修正了这个bug,并注意到已经有相应的补丁,所有这些信息我们都能得到。很多次我都发现,所遇到的错误以前已经出现过,而且事实上已经有了修正和解决的办法。

3.2.3             跟踪文件小结

现在你知道有两种一般的跟踪文件,它们分别放在什么位置,以及如何找到这些跟踪文件。希望你使用跟踪文件主要是为了调整和改善应用的性能,而不只是提交 iTAR。最后再说一句,Oracle Support确实会利用文档中没有记录的一些“事件”,如果数据库遭遇错误,可以利用这些事件得到大量的诊断信息。例如,如果得到一个ORA-01555,但你自认为不该有这个错误,此时Oracle Support就会教你设置这种诊断事件,每次遇到错误时都会创建一个跟踪文件,由此可以帮助你准确地跟踪到为什么会产生错误。

3.3   警告文件

警告文件(也称为警告日志(alert log))就是数据库的日记。这是一个简单的文本文件,从数据库“出生”(创建)那一天起就会编写该文件,直到数据库“完结”(被你删除)为止。在这个文件中,可以看到数据库的“编年史”,包括日志开关;可能出现的内部错误;表空间何时创建、离线以及恢复为在线,等等。这是一个查看数据库历史的极其有用的文件。我喜欢让警告文件尽量地增长,直到非常大了才会对其“编卷”(归档)。在我看来,这个文件里的信息越多越好。

我不会介绍警告日志里的每一处细节,这个范围实在太大了。不过,建议你把自己的警告日志拿来看看,你会发现其中的大量信息。在这一节中,我们会介绍一个特定的例子,并通过这个例子来说明如何挖掘警告日志中的信息,并建立一个正常运行报告。

最近我利用http://asktom.oracle.com网站的警告日志文件生成了我的数据库的一个正常运行报告。我不想全面盘查文件,然后手动地得到报告(警告文件中有关闭和启动时间),而是决定充分利用数据库和SQL来自动完成,所以我开发了一种技术,从而由警告日志直接创建动态的正常运行报告。

通过EXTERNAL TABLE(第10章将更详细地介绍)可以查询警告日志,并了解其中有什么。我发现,每次启动数据库时警告日志里都会产生几天记录:

Thu May 6 14:24:42 2004

Starting ORACLE instance (normal)

这是一个时间戳记录(定宽格式),还有一条消息:Starting ORACLE instance。我还注意到,在这些记录前面,可能有一个ALTER DATABASE CLOSE消息(正常关闭期间)或者一个关闭异常中止的消息,也可能“什么也没有”,没有消息,这意味着系统崩溃了。但是只要有消息,就肯定有相关的每个时间戳。所以,只要系统没有“崩溃”,就会在警告日志里记录一些有意义的时间戳(如果系统崩溃了,也会记录崩溃前不久的一个时间戳,因为警告日志写得相当频繁)。

我注意到,如果做到以下几条,就能很容易地生成一个正常运行报告:

q         收集所有Starting ORACLE instance %之类的记录。

q         收集所有与日期格式匹配的记录(实际上就是日期)。

q         将每个Starting ORACLE instance记录与前面的两个记录想关联(前面的两个记录应该是日期)。

以下代码创建了一个外部表,以便查询警告日志(注意:要把/background/dump/dest/换成你自己的后台转储目标目录,并在CREATE TABLE语句中使用你自己的警告日志名)。

ops$tkyte@ORA 10G > create or replace directory data_dir as '/background/dump/dest/'

2 /

Directory created.

 

ops$tkyte@ORA 10G > CREATE TABLE alert_log

2          (

3                   text_line varchar2(255)

4          )

5          ORGANIZATION EXTERNAL

6          (

7                   TYPE ORACLE_LOADER

8                   DEFAULT DIRECTORY data_dir

9                   ACCESS PARAMETERS

10                (

11                         records delimited by newline

12                         fields

13                         REJECT ROWS WITH ALL NULL FIELDS

14                )

15                LOCATION

16                (

17                         'alert_AskUs.log'

18                )

19       )

20       REJECT LIMIT unlimited

21 /

Table created.

这样任何时间都能查询这些信息了:

ops$tkyte@ORA 10G > select to_char(last_time,'dd-mon-yyyy hh24:mi') shutdown,

2                   to_char(start_time,'dd-mon-yyyy hh24:mi') startup,

3                   round((start_time-last_time)*24*60,2) mins_down,

4                   round((last_time-lag(start_time) over (order by r)),2) days_up,

5                   case when (lead(r) over (order by r) is null )

6                            then round((sysdate-start_time),2)

7                   end days_still_up

8          from (

9 select r,

10                to_date(last_time, 'Dy Mon DD HH24:MI:SS YYYY') last_time,

11                to_date(start_time,'Dy Mon DD HH24:MI:SS YYYY') start_time

12 from (

13 select r,

14                text_line,

15                lag(text_line,1) over (order by r) start_time,

16                lag(text_line,2) over (order by r) last_time

17 from (

18 select rownum r, text_line

19 from alert_log

20 where text_line like '___ ___ __ __:__:__ 20__'

21       or text_line like 'Starting ORACLE instance %'

22        )

23       )

24 where text_line like 'Starting ORACLE instance %'

25       )

26 /

SHUTDOWN             STARTUP                            MINS_DOWN DAYS_UP    DAYS_STILL_UP

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

                                          06-may-2004 14:00

  06-may-2004 14:24   06-may-2004 14:24                     .25                 .02                                   

  10-may-2004 17:18   10-may-2004 17:19                     .93               4.12                                   

    26-jun-2004 13:10     26-jun-2004 13:10                     .65             46.83                                   

   07-sep-2004 20:13    07-sep-2004 20:20                   7.27             73.29                      116.83

这里不会详细讨论SQL查询的细节,不过要知道,第1821行的最内层查询用于收集“Starting”消息和日期行记录(记住,使用LIKE子句时,“_”只匹配一个字符,不多不少只能是一个字符)。通过使用ROWNUM还对行”编号“。然后,下一层查询(外层查询)使用内置的LAG()分析函数,对每一行记录,分别返回到其前一行及前两行,然后将数据综合起来,这样查询的第3行就同时包含了第1行、第2行和第3行的数据。相应地,第4行就有了第2行、第3行和第4行的数据,依此类推。最后只留下形如Starting ORACLE instance %的行,而且现在每一行都有了前面的两个相关的时间戳。从这个查询结果计算停机数据就很容易了:只需将两个日期相减。计算正常运行时间也不难(你已经了解了LAG()函数的作用):只需回到前一行,得到其启动时间,再将当前行的停机时间减去前一行的启动时间,就可以得到正常运行时间。

我的Oracle 10g 数据库是 56日 启动的,其间关闭过4次(到编写这本书时,它已经连续运行了116.83天)。平均正常运行时间越来越好(要知道,利用强大的SQL,我们还能很轻松地计算出平均运行时间的改进程度)。

如果你对此很感兴趣,想再看一个从警告日志中挖掘有用信息的例子,可以访问http://asktom.oracle.com/~tkyte/alert_arch.html。这个网页演示了如果计算将给定在线重做日志文件归档所用的平均时间。一旦了解了警告日志中有些什么,你自己来生成这些查询就很容易了。

3.4   数据文件

数据文件和重做日志文件是数据库中最重要的文件。你的数据最终就是要存储在数据文件中。每个数据库都至少有一个相关的数据文件,通常还不止一个。最简单的“测试”数据库只有一个数据文件。实际上,在第2章中我们已经见过一个例子,其中用最简单的CREATE DATABASE命令根据默认设置创建了一个数据库,这个数据库中有两个数据文件,其中一个对应SYSTEM表空间(真正的Oracle数据字典),另一个对应SYSAUX表空间(在 10g 及以上版本中,非字典对象都存储在这个表空间中)。不过,所有实际的数据库都至少有3个数据文件;一个存储SYSTEM数据,一个存储SYSAUX数据,还有一个存储USER数据。

简要回顾文件系统类型之后,我们将讨论如何组织这些文件,以及文件中如何组织数据。要了解这些内容,需要知道什么是表空间(tablespace)、什么是段(segment)、什么是区段(extent),以及什么是块(block)。这些都是Oracle在数据库中存储对象所用的分配单位,稍后将详细介绍。

3.4.1             简要回顾文件系统机制

Oracle中,可以用4种文件系统机制存储你的数据。这里强调了“你的数据”,是指你的数据字典、redo记录、undo记录、表、索引、LOB等,也就是你自己每天关心的数据。简单地讲,这包括:

q         Cooked”操作系统(OS)文件系统:这些文件就像字处理文档一样放在文件系统中。在Windows 资源管理器中可以看到这些文件,在UNIX上,可以通过ls命令看到这些文件。可以使用简单的OS工具(如Windows上的xcopyUNIX上的cp)来移动文件。从历史上看,Cooked OS文件一直是Oracle中存储数据的“最流行”的方法,不过我个人认为,随着ASM(稍后再详细说明)的引入,这种情况会有所改观。Cooked文件系统(“加工”文件系统或“熟”文件系统)通常也会缓存,这说明在你读写磁盘时,OS会为你缓存信息。

q         原始分区(raw partitions,也称裸分区):这不是文件,而是原始磁盘。不能用ls来查看;不能在Windows资源管理器中查看其内容。它们就是磁盘上的一些大扇区,上面没有任何文件系统。对Oracle来说,整个原始分区就是一个大文件。这与cooked文件系统不同,cooked文件系统上可能有几十个甚至数百个数据库数据文件。目前,只有极少数Oracle安装使用原始分区,因为原始分区的管理开销很大。原始分区不是缓冲设备,所完成的所有I/O都是直接I/O,对数据没有任何OS缓冲(不过,对于数据库来说,这通常是一个优点)。

q         自动存储管理(Automatic Storage ManagementASM):这是 Oracle 10g Release 1 的一个新特性(标准版和企业版都提供了这个特性)。ASM是专门为数据库设计的文件系统。可以简单地把它看作一个数据库文件系统。在这个文件系统上,不是把购物清单存储在文本文件中;这里只能存储与数据库相关的信息:你的表、索引、备份、控制文件、参数文件、重做日志、归档文件等。不过,即使是ASM,也同样存在着相应的数据文件;从概念上讲,数据库仍存储在文件中,不过现在的文件系统是ASMASM设计成可以在单机环境或者集群环境中工作。

q         集群文件系统:这个文件系统专用于RAC(集群)环境,看上去有些像由集群环境中多个节点(计算机)共享的cooked文件系统。传统的cooked文件系统只能由集群环境中的一台计算机使用。所以,尽管可以在集群中的多个节点之间使用NFS装载或Samba共享一个cooked文件系统(SambaNFS类似,可以在Windows/UNIX环境之间共享磁盘),但这会导致一损俱损。如果安装有文件系统并提供共享的节点失败,这个文件系统都将不可用。Oracle集群文件系统(Oracle Cluster File SystemOCFS)是Oracle在这个领域推出的一个新的文件系统,目前只能在WindowsLinux上使用。其他第三方开发商也提供了一些经认证的集群文件系统,也可以用于Oracle。集群文件系统让cooked文件系统的优点延伸到了集群环境中。

有意思的是,数据库可能包含来自上述所有文件系统中的文件,你不必只选其中的一个。在你的数据库中,可能部分数据存储在一个传统的cooked文件系统中,有些在原始分区上,有一些在ASM中,还有一些在集群文件系统中。这样就能很容易地切换技术,或者只是涉及一个新的文件系统,而不必把整个数据库都搬到这个文件系统中。现在,因为完整地讨论文件系统及其详细的属性超出了本书的范围,所以我们还是回过头来深入探讨Oracle文件类型。不论文件是存储在cooked文件系统、原始分区、ASM中,还是存储在集群文件系统中,以下概念都适用。

3.4.2             Oracle数据库中的存储层次体系

数据库由一个或多个表空间构成。表空间(tablespace)是Oracle 中的一个逻辑存储容器,位于存储层次体系的顶层,包括一个或多个数据文件。这些文件可能是文件系统中的cooked文件、原始分区、ASM管理的数据库文件,或者是集群文件系统上的文件。表空间包含段,请看下面的介绍。

1.     

现在开始分析存储层次体系,首先讨论段,这是表空间中主要的组织结构。段(segment)就是占用存储空间的数据库对象,如表、索引、回滚段等。创建表时,会创建一个表段。创建分区表时,则每个分区会创建一个段。创建索引时,就会创建一个索引段,依此类推。占用存储空间的每一个对象最后都会存储在一个段中,此外还有回滚段(rollback segment)、临时段(temporary segment)、聚簇段(cluster segment)、索引段(index segment)等。

注意    上面有这样一句话:“占用存储空间的每一个对象最后都会存储在一个段中”,这可能会把你搞糊涂。你会发现许多CREATE语句能创建多段的对象。之所以会产生困惑,原因是一条CREATE语句最后创建的对象可能包含0个、1个或多个段!例如,CREATE TABLE T ( x int primary key, y clob)就会创建4个段:一个是TABLE T的段,还有一个段对应索引(这个索引是为支持主键而创建的),另外还有两个CLOB段(一个CLOB段是LOB索引,另一个段是LOB数据本身)。与之不同,CREATE TABLE T ( x int, y date ) cluster MY_CLUSTER则不会创建任何段。第10章还会更深入地讨论这个概念。

2.      区段

段本身又由一个或多个区段组成。区段(extent)是文件中一个逻辑上连续分配的空间(一般来讲,文件本身在磁盘上并不是连续的;否则,根本就不需要消除磁盘碎片的工具了!)。另外,利用诸如独立磁盘冗余阵列(Redundant Array of Independent DisksRAID)之类的磁盘技术,你可能会发现,一个文件不仅在一个磁盘上不连续,还有可能跨多个物理磁盘。每个段都至少有一个区段,有些对象可能还需要至少两个区段(回滚段就至少需要两个区段)。如果一个对象超出了其初始区段,就会请求再为它分配另一个区段。第二个区段不一定就在磁盘上第一个区段旁边,甚至有可能不在第一个区段所在的文件中分配。第二个区段可能与第一个区段相距甚远,但是区段内的空间总是文件中的一个逻辑连续空间。区段的大小可能不同,可以是一个Oracle数据块,也可以大到2 GB

3.     

区段又进一步由块组成。块(block)是Oracle中最小的空间分配单位。数据行、索引条目或临时排序结果就存储在块中。通常Oracle从磁盘读写的就是块。Oracle中块的常见大小有4种:2 KB4 KB8 KB16 KB(尽管在某些情况下32 KB也是允许的;但是操作系统可能对最大大小有限制)。

注意    有一点可能很多人都不知道:数据库的默认块大小不必是2的幂。2的幂只是一个常用的惯例。实际上,你完全可以创建块大小为5 KB7 KBn KB的数据库,这里n介于232 KB之间。不过,我还是建议你在实际中不要考虑这样做,块大小还是用2 KB4 KB8 KB16 KB比较好。

段、区段和数据块之间的关系如图3-1所示。

一个段由一个或多个区段组成,区段则由连续分配的一些块组成。从Oracle9i Release 1起,数据库中最多可以有6种不同的块大小(block size)。

3-1 段、区段和数据块

注意    之所以引入这个特性,即一个数据库中允许有多种块大小,目的是为了可以在更多的情况下使用可传输的表空间。如果能传输表空间,DBA就能从一个数据库移动或复制格式化的数据文件,把它放在另一个数据库中,例如,可以从一个联机事务处理(Online Transaction ProcessingOLTP)数据库中把所有表和索引复制到一个数据仓库(Data WarehouseDW)中。不过,在许多情况下,OLTP数据库使用的块大小可能很小,如2 KB4 KB,而DW使用的块大小可能很大(8 KB16 KB)。如果一个数据库中不支持多种块大小,就无法传输这些信息。有多种块大小的表空间主要用于传输表空间,一般没有其他用途。

数据库还有一个默认的块大小,即执行CREATE DATABASE命令时初始化文件中指定的大小。SYSTEM表空间总是使用这个默认块大小,不过你完全可以按非默认块大小(2 KB4 KB8 KB16 KB)创建其他表空间,如果操作系统允许,还可以使用32 KB的块大小。当且仅当创建数据库时指定了一个非标准的块大小(不是2的幂)时,才会有6种不同的块大小。因此,在实际中,数据库最多有5种不同的块大小:默认大小和另外4种非默认的块大小。

在所有给定的表空间内部,块大小都是一致的,这说明,一个表空间中的所有块大小都相同。对于一个多段对象,如一个包含LOB列的表,可能每个段在不同的表空间中,而这些表空间分别有不同的块大小,但是任何给定段(包含在表空间中)都由相同大小的块组成。无论大小如何,所有块格式都一样,如图3-2所示。

3-2 块结构

块首部(block header)包含块类型的有关信息(表块、索引块等)、块上发生的活动事务和过去事务的相关信息(仅事务管理的块有此信息,例如临时排序块就没有事务信息),以及块在磁盘上的地址(位置)。块中接下来两部分是表目录和行目录,最常见的数据库块中(即堆组织表的数据块)都有这两部分。第10章将更详细地介绍数据库表类型,不过,现在知道大多数表都是这种类型就足够了。如果有表目录(table directory),则其中会包含把行存储在这个块上的表的有关信息(可能一个块上存储了多个表的数据)。行目录(row directory)包含块中行的描述信息。这是一个指针数组,指向块中数据部分中的行。块中的这3部分统称为块开销(block overhead),这部分空间并不用于存放数据,而是由Oracle用来管理块本身。块中余下的两部分就很清楚了:块上可能有一个空闲空间(free space),通常还会有一个目前已经存放数据的已用空间(used space)。

从以上介绍可以知道,段由区段组成,区段由块组成,对段有了大致的了解后,下面再来更深入地分析表空间,然后说明文件在这个存储层次体系中的位置。

4.      表空间

前面已经提到,表空间是一个容器,其中包含有段。每个段都只属于一个表空间。一个表空间中可能有多个段。一个给定段的所有区段都在与段相关联的表空间中。段绝对不会跨越表空间边界。表空间本身可以有一个或多个相关的数据文件。表空间中给定段的一个区段完全包含在一个数据文件中。不过,段可以有来自多个不同数据文件的区段。表空间如图3-3所示。

3-3  这个表空间包含两个数据文件、3个段和4个区段

3-3显示了一个名为USER_DATA的表空间。其中包括两个数据文件:user_data01user_data02。并分配了3个段:T1T2I1(可能是两个表和一个索引)。这个表空间中分配了4个区段,每个区段表示为逻辑上连续分配的一组数据库块。段T1包括两个区段,分别在不同的文件中。段T2I1都各有一个区段。如果这个表空间需要更多的空间,可以调整已经分配给表空间的数据文件的大小,或者可以再增加第三个数据文件。

表空间是Oracle中的逻辑存储容器。作为开发人员,我们会在表空间中创建段,而绝对不会深入到原始的“文件级”。我们可不希望在一个特定的文件中分配区段(当然这也是可以的,但我们一般都不会这么做)。相反,我们会在表空间中创建对象,余下的工作都由Oracle负责。如果将来某个时刻DBA决定在磁盘上移动数据文件,从而使I/O分布得更均匀,这对我们来说没有任何关系,它根本不会影响我们的处理。

5.      存储层次体系小结

总结一下,Oracle中的存储层次体系如下:

(1) 数据库由一个或多个表空间组成。

(2) 表空间由一个或多个数据文件组成。这些文件可以是文件系统中的cooked文件、原始分区、ASM管理的数据库文件,或集群文件系统上的文件。表空间包含段。

(3) 段(TABLEINDEX等)由一个或多个区段组成。段在表空间中,但是可以包含这个表空间中多个数据文件中的数据。

(4) 区段是磁盘上一组逻辑连续的块。区段只在一个表空间中,而且总是在该表空间内的一个文件中。

(5) 块是数据库中最小的分配单位,也是数据库使用的最小I/O单位。

3.4.3             字典管理和本地管理的表空间

在继续讨论之前,我们再来看看关于表空间的一个问题:在表空间中如何管理区段。在Oracle 8.1.5 之前,表空间中管理区段的分配只有一种方法:字典管理的表空间(dictionary-managed tablespace)。也就是说,表空间中的空间在数据字典表中管理,这与管理账户数据(利用DEBITCREDIT表)的方法是一样的。借方有已经分配给对象的所有区段。贷方是所有可用的自由区段。如果一个对象需要另一个区段,就会向系统“申请”。然后Oracle访问其数据字典表,运行一些查询,查找到空间(也许找不到),然后更新一个表中的一行(或者从表中将这一行删除),再向另一个表插入一行。Oracle管理空间与你编写应用可谓异曲同工:同样是要修改数据以及移动数据。

为了得到额外的空间而在后台代表你执行的SQL称为递归SQLrecursive SQL)。你的SQL INSERT语句会导致执行其他递归SQL来得到更多空间。如果频繁地执行这种递归SQL,开销可能相当大。对数据字典的这种更新必须是串行的;它们不能同时进行,所以要尽量避免。

Oracle的早期版本中,可以看到,这种空间管理问题(递归SQL开销)在“临时表空间”中最常见(这还不是“真正的”临时表空间,真正的临时表空间是通过CREATE TEMPORARY TABLESPACE命令创建的)。空间会频繁地分配(从字典表删除,而插入到另一个表)和撤销(把刚移动的行再移回原来的位置)。这些操作必须串行执行,这就大大削弱了并发性,而增加了等待时间。在7.3版本中,Oracle引入了一个真正的临时表空间(true temporary tablespace)概念,这是一个新的表空间类型,专门用于存储临时数据,从而帮助缓解这个问题。在引入这个特殊的表空间类型之前,临时数据与永久数据在同样的表空间中管理,处理方式也与永久数据一样。

而临时表空间则不同,你不能在其中创建自己的永久对象。实际上根本的区别只有这一条;空间还是在数据字典表中管理。不过,一旦在临时表空间中分配了一个区段,系统就会一直持有(也就是说,不会把空间交回)。下一次有人出于某种目的在临时表空间中请求空间时,Oracle会在其内部的已分配区段列表中查找已经分配的区段。如果找到,就会直接重用,否则还是用老办法来分配一个区段。采用这种方式,一旦数据库启动,并运行一段时间,临时段看上去就好像满了,但是实际上只是“已分配”。里面都是空闲区段,它们的管理完全不同。当有人需要临时空间时,Oracle会在内存中的数据结构里查找空间,而不是执行代价昂贵的递归SQL

Oracle 8.1.5 及以后版本中,Oracle在减少这种空间管理开销方面又前进了一步。它引入了一个本地管理表空间(locally-managed tablespace )概念,而不是字典管理表空间。与Oracle 7.3中对临时表空间的管理一样,本地空间管理采用了同样的办法来管理所有表空间:这样就无需使用数据字典来管理表空间中的空间。对于本地管理表空间,会使用每个数据文件中存储的一个位图来管理区段。现在要得到一个区段,系统所做的只是在位图中将某一位设置为1。要释放空间,系统再把这一位设置为0。与使用字典管理的表空间相比,这样分配和释放空间就相当快。为了处理跨所有表空间的空间请求,我们不再需要在数据库级串行完成这些耗时的操作,相反,只需在表空间级串行执行一个速度相当快的操作。本地管理的表空间还有另外一些很好的特点,如可以保证区段的大小统一,不过这一点DBA更关心。

再往后,则只应使用本地管理的表空间作为存储管理方法。实际上,在Oracle9i及以上版本中,如果使用数据库配置助手(database configuration assistantDBCA)创建一个数据库,它就会创建一个SYSTEM作为本地管理的表空间,如果SYSTEM是本地管理的,那么该数据库中所有其他表空间也会是本地管理的,而且遗留的字典管理方法将无法工作。如果数据库中的SYSTEM是本地管理的表空间,并不是说这样的数据库中不支持字典管理的表空间,而是说其中根本无法创建字典管理的表空间:

ops$tkyte@ORA 10G > create tablespace dmt

2 datafile '/tmp/dmt.dbf' size 2m

3 extent management dictionary;

create tablespace dmt

*

ERROR at line 1:

ORA-12913: Cannot create dictionary managed tablespace

ops$tkyte@ORA 10G > !oerr ora 12913

12913, 00000, "Cannot create dictionary managed tablespace"

// *Cause: Attempt to create dictionary managed tablespace in database

// which has system tablespace as locally managed

// *Action: Create a locally managed tablespace.

这是一个正面的副作用,因为这样可以杜绝你使用遗留的存储机制,要知道它的效率相对较低,而且很可能导致碎片。本地管理的表空间除了在空间分配和撤销方面效率更高以外,还可以避免出现表空间碎片,这正是以本地管理表空间的方式分配和撤销空间的一个副作用。有关内容将在第10章更深入地讨论。

3.5   临时文件 

Oracle中的临时数据文件(Temporary data files)即临时文件(temp files)是一种特殊类型的数据文件。Oracle使用临时文件来存储大规模排序操作和散列操作的中间结果,如果RAM中没有足够的空间,还会用临时文件存储全局临时表数据,或结果集数据。永久数据对象(如表或索引)不会存储在临时文件中,但是临时表及其索引的内容要存储在临时文件中。所以,你不可能在临时文件中创建表,但是使用临时表时完全可以在其中存储数据。

Oracle以一种特殊的方式处理临时文件。一般而言,你对对象所做的每一个修改都会存储在重做日志中;这些事务日志会在以后某个时间重放以“重做事务”,例如,失败后进行恢复时就可能需要“重做事务”。临时文件不包括在这个重放过程内。对临时文件并不生成redo日志,不过可以生成undo日志。由于UNDO总是受redo的“保护”,因此,这就会生成使用临时表的redo日志,有关详细内容见第9章。为全局临时表生成undo日志的目的是为了回滚在会话中所做的一些工作,这可能是因为处理数据时遇到一个错误,也可能因为某个一般性的事务失败。DBA不需要备份临时数据文件,实际上,备份临时数据文件只会浪费时间,因为你无法恢复临时数据文件。

建议将数据库配置为使用本地管理的临时表空间。作为DBA,要确保使用CREATE TEMPORARY TABLESPACE命令。你肯定不想把一个永久表空间改成临时表空间,因为这样得不到临时文件的任何好处。

关于真正的临时文件,有一个细节需要注意,如果操作系统允许创建临时文件,则会稀疏(sparse)地创建,也就是说,在需要之前它们不会真正占用磁盘存储空间。通过下面这个例子能很容易看出这一点(这里的平台是Red Hat Linux):

ops$tkyte@ORA 10G > !df

Filesystem   1K-blocks             Used          Available        Use%           Mounted on

/dev/hda2    74807888    41999488        29008368           60%           /

/dev/hda1         102454           14931               82233           16%           /boot

none               1030804                     0           1030804             0%           /dev/shm

 

ops$tkyte@ORA 10G > create temporary tablespace temp_huge

2 tempfile '/d01/temp/temp_huge' size 2048m

3 /

Tablespace created.

 

ops$tkyte@ORA 10G > !df

Filesystem   1K-blocks             Used          Available        Use%           Mounted on

/dev/hda2    74807888    41999616        29008240           60%           /

/dev/hda1         102454           14931               82233           16%           /boot

none               1030804                     0           1030804             0%           /dev/shm

注意    df是显示“磁盘空闲空间”的Unix命令。这个命令显示出,向数据库中添加一个2 GB的临时文件之前,包含/d01/temp的文件系统中有29 008 368 KB的空闲空间。添加了这个文件之后,文件系统中有29 008 240 KB的空闲空间。

显然,这个文件只占了128 KB的存储空间,但是,如果用ls将其列出,可以得到:

ops$tkyte@ORA 10G > !ls -l /d01/temp/temp_huge

-rw-rw---- 1 ora 10g ora 10g 2147491840 Jan 2 16:34 /d01/temp/temp_huge

看上去是一个正常的2 GB文件,但它实际上只用了128 KB的存储空间。之所以要指出这一点,原因是我们实际上可能创建了数百个2 GB的临时文件,尽管空闲的磁盘空间只有大约29 GB。听起来不错,空闲空间那么多!问题是,真正开始使用这些临时文件时,它们就会膨胀,很快我们就会得到“没有更多空间”的错误。由于空间会按操作系统的需要来分配或者物理地分配文件,所以我们肯定会用光空间(特别是这样一种情况,我们创建了临时文件后,有人又用其他内容把文件系统填满了,此时临时文件实际上根本没有可用的空间)。

这个问题的解决因操作系统而异。在Linux上,可以使用dd在文件中填入数据,这样,操作系统就会物理地为文件分配磁盘空间,或者使用cp创建一个非稀疏的文件,例如:

ops$tkyte@ORA 10G > !cp --sparse=never /d01/temp/temp_huge /d01/temp/temp_huge2

 

ops$tkyte@ORA 10G > !df

Filesystem   1K-blocks             Used          Available        Use%           Mounted on

/dev/hda2    74807888    44099336        26908520           63%           /

/dev/hda1         102454           14931               82233           16%           /boot

none               1030804                     0           1030804             0%           /dev/shm

 

ops$tkyte@ORA 10G > drop tablespace temp_huge;

Tablespace dropped.

 

ops$tkyte@ORA 10G > create temporary tablespace temp_huge

2 tempfile '/d01/temp/temp_huge2' reuse;

Tablespace created.

 

ops$tkyte@ORA 10G > !df

Filesystem   1K-blocks             Used          Available        Use%           Mounted on

/dev/hda2    74807888    44099396        26908460           63%           /

/dev/hda1         102454           14931               82233           16%           /boot

none               1030804                     0           1030804             0%           /dev/shm

将稀疏的2 GB文件复制到/d01/temp/temp_huge2中,并使用REUSE选项利用该临时文件创建临时表空间,这样就能肯定这个临时文件已经分配了所有文件系统空间,而且数据库确实有了2 GB的临时空间可以使用。

注意    根据我的经验,Windows NTFS不支持稀疏文件,以上讨论只适用于UNIX/Linux平台。好的一面是,如果必须在UNIX/Linux上创建一个15 GB的临时表空间,而且支持临时文件,你会发现创建过程相当快(几乎立即完成),但是要保证确实有15 GB的空闲空间,而且一定要记住保留这些空间。

3.6   控制文件 

控制文件(control file)是一个相当小的文件(最多能增长到64 MB左右),其中包含Oracle需要的其他文件的一个目录。参数文件告知实例控制文件的位置,控制文件则告知实例数据库和在线重做日志文件的位置。

控制文件还告知了Oracle其他一些事情,如已发生检查点的有关信息、数据库名(必须与DB_NAME参数匹配)、创建数据库的时间戳、归档重做日志的历史(有时这会让控制文件变大)、RMAN信息等。

控制文件应该通过硬件(RAID)多路保存,如果不支持镜像,则要通过Oracle多路保存。应该有不止一个副本,而且它们应该保存在不同的磁盘上,以防止万一出现磁盘故障而丢失控制文件。丢失控制文件并不是致命的,但会使恢复变得困难得多。

开发人员实际上可能不会接触到控制文件。对于DBA来说,控制文件是数据库中一个非常重要的部分,但是对于软件开发人员,它们并不是太重要。

3.7   重做日志文件 

重做日志文件(redo log file)对于Oracle数据库至关重要。它们是数据库的事务日志。通常只用于恢复,不过也可以用于以下工作:

q         系统崩溃后的实例恢复

q         通过备份恢复数据文件之后恢复介质

q         备用(standby)数据库处理

q         输入到流中,这是一个重做日志挖掘过程,用于实现信息共享(这也是一种奇特的复制)

重做日志文件的主要目的是,万一实例或介质失败,重做日志文件就能派上用场,或者可以作为一种维护备用数据库(standby database)的方法来完成故障恢复。如果数据库所在主机掉电,导致实例失败,Oracle会使用在线重做日志将系统恢复到掉电前的那个时刻。如果包含数据文件的磁盘驱动器出现了永久性故障,Oracle会使用归档重做日志以及在线重做日志,将磁盘驱动器的备份恢复到适当的时间点。另外,如果你“无意地”删除了一个表,或者删掉了一些重要的信息,而且提交了操作,则可以恢复一个备份,并让Oracle使用这些在线和归档重做日志文件将其恢复到意外发生前的那个时刻。

你在Oracle中完成的每个操作几乎都会生成一定的redo信息,并写入在线重做日志文件。向表中插入一行时,插入的最终结果会写入重做日志。删除一行时,则会在重做日志中写入你删除了这一行这一事实。删除一个表时,删除的效果会写入重做日志。从表中删除的数据不会写入;不过,Oracle删除表时执行的递归SQL确实会生成redo。例如,OracleSYS.OBJ$表(和其他内部字典对象)中删除一行时,这就会生成redo,另外如果支持不同模式的补充日志(supplemental logging ),还会把具体的DROP TABLE语句写入重做日志流。

有些操作可能会以尽量少生成redo的模式完成。例如,可以使用NOLOGGING属性创建一个索引。这说明,最初创建索引数据的操作不会记入日志,但是Oracle完成的所有递归SQL会写入日志。例如,创建索引后,将向SYS.OBJ$表中插入一行表示索引存在,这个插入会记入日志,以后使用SQL插入、更新和删除等操作完成的修改也会记入日志。但是,最初向磁盘写索引结构的操作不会记入日志。

前面我提到了两种类型的重做日志文件:在线(online)和归档(archived)。下面几节将详细介绍这两类重做日志文件。在第9章中,我们还会结合回滚段来讨论redo,看看它们对开发人员有什么影响。现在,我们只关注这些重做日志文件是什么,它们有什么用途。

3.7.1             在线重做日志

每个Oracle数据库都至少有两个在线重做日志文件组。每个重做日志组都包含一个或多个重做日志成员(redo按成员组来管理)。这些组的单个重做日志文件成员之间实际上形成彼此真正的镜像。这些在线重做日志文件的大小是固定的,并以循环方式使用。Oracle先写日志文件组1,当到达这组文件的最后时,会切换至日志文件组2,从头到尾重写这些文件的内容。日志文件组2填满时,再切换回到日志文件组1(假设只有两个重做日志文件组;如果有3个重做日志文件组,当然会继续写第3个组)。如图3-4所示。


3-4  日志文件组

从一个日志文件组切换到另一个日志文件组的动作称为日志切换(log switch)。重要的是注意到,如果数据库配置得不好,日志切换可能会导致临时性“暂停”。由于重做日志的目的是在失败时恢复事务,所以我们自己必须保证一点:在重用重做日志之前,失败时应该不需要重做日志文件的内容。如果Oracle不能肯定这一点,也就是说,它不清楚是否真的不需要日志文件的内容,就会暂时挂起数据库中的操作,确保将缓存中的数据(即redo“保护”的数据)安全地写入磁盘本身(建立检查点)。一旦Oracle能肯定这一点,再恢复处理,并重用重做文件。

我们刚刚提到一个重要的数据库概念:检查点(checkpointing)。要理解在线重做日志如何使用,就需要了解检查点,知道数据库缓冲区缓存如何工作,还要知道一个称为数据块写入器(data block writerDBWn)的进程会做什么。数据库缓冲区缓存和DBWn将在后面详细讨论,但是我们先提前说两句,不过点到为止。

数据库缓冲区缓存(database buffer cache)就是临时存储数据库块的地方。这是Oracle SGA中的一个结构。读取块时,会存储在这个缓存中,这样以后就不必再物理地重新读取它们。缓冲区缓存首先是一个性能调优设备,其目的只是让非常慢的物理I/O过程看上去快一些。修改块(更新块上的一行)时,这些修改会在内存中完成,写至缓冲区缓存中的块。另外,会把重做这些修改所需的足够信息保存在重做日志缓冲区(redo log buffer)中,这是另一个SGA数据结构。提交(COMMIT)修改时,会使这些修改成为永久的。Oracle并不是访问SGA中修改的所有块,并把它们写到磁盘上。相反,它只是把重做日志缓冲区的内容写到在线重做日志中。只要修改的块还在缓冲区缓存中,而不在磁盘上,数据库失败时我们就会需要该在线重做日志的内容。如果提交过后,突然掉电,数据库缓冲区缓存就会彻底清空。

如果发生这种情况,则只有重做日志文件中有修改记录。重启数据库时,Oracle实际上会重放我们的事务,再用同样的方式修改块,并提交。所以,只要修改的块被缓存而未写入磁盘,就不能重用重做日志文件。

在这里DBWn就能起作用了。这是Oracle的一个后台进程,负责在缓冲区缓存填满时请求空间,更重要的是,它会建立检查点。建立检查点就是把脏块(已修改的块)从缓冲区缓存写至磁盘。Oracle会在后台为我们做这个工作。有很多情况都会导致建立检查点,最常见的事件就是重做日志切换。

在填满日志文件1并切换到日志文件2时,Oracle就会启动一个检查点。此时,DBWn开始将日志文件组1所保护的所有脏块写至磁盘。在DBWn把该日志文件保护的所有块刷新输出之前,Oracle不能重用这个日志文件。如果DBWn在完成其检查点之前就想使用日志文件,就会在数据库的ALERT日志中得到以下消息:

...

Thread 1 cannot allocate new log, sequence 66

Checkpoint not complete

Current log# 2 seq# 65 mem# 0: C:/ORACLE/ORADATA/ORA 10G /REDO02.LOG

...

所以,出现这个消息时,数据库中的处理会挂起,因为DBWn正忙于完成它的检查点。此时,Oracle会尽可能地把所有处理能力都交给DBWn,希望它能更快地完成。

如果数据库实例得到了妥善地调优,是不会看到这个消息的。如果你确实看到了这个消息,就应该知道肯定让最终用户陷入了不必要的等待,而这是可以避免的。我们的目标是分配足够的在线重做日志文件(这是对DBA而言,对开发人员则不一定),这样就不会在检查点完成之前试图重用日志。如果经常看到这个消息,这说明DBA未能为应用分配足够多的在线重做日志文件,或者要对DBWn进行调优才能更高效地工作。

不同的应用会生成不同数量的重做日志。很自然地,决策支持系统(Decision Support SystemDSS,仅查询)或数据仓库(DW)系统生成的在线重做日志总是比OLTP(事务处理)系统生成的在线重做日志少得多。如果一个系统在数据库中对二进制大对象(Binary Large ObjectBLOB)完成了大量图像处理,相对于简单的订单输入系统来说,则会生成更多的redo。有100位用户的订单输入系统与有1,000位用户的系统相比,生成的redo可能只是后者的十分之一。至于重做日志多大才合适,这没有“正确”的答案,不过你肯定希望重做日志足够大,能适应你的工作负载。

在设置在线重做日志的大小和数目时,还有一些问题需要考虑。其中很多问题都超出了这本书的范围,不过在此把它们都列出来,以便你有一个大致的认识:

q         高峰负载(peak workload):你可能希望系统不必等待对未完成的消息建立检查点,不要在高峰处理期间遭遇瓶颈。你不能针对“平均”的小时吞吐量来确定重做日志的大小,而要针对高峰处理来确定。如果每天生成24 GB的日志,但是其中10 GB的日志都是在9:00 am11:00 am这一时段生成的,就要把重做日志的大小调整到足以放下那两小时高峰期间生成的日志。如果只是针对每小时1 GB来确定日志大小可能是不够的。

q         大量用户修改相同的块:如果大量用户都要修改相同的块,你可能希望重做日志文件很大。因为每个人都在修改同样的块,最好尽可能多地更新之后才将其写出到磁盘。每个日志切换都会导致一个检查点,所以你可能不希望频繁地切换日志。不过,这样一来又会影响恢复时间。

q         平均恢复时间:如果必须确保恢复尽可能快地完成,即便是大量用户要修改相同的块,也可能倾向于使用较小的重做日志文件。如果只是处理一两个小的重做日志文件,而不是一个巨大的日志文件,则所需的恢复时间会比较短。由于重做日志文件小,往往会过多地建立检查点,时间长了,整个系统会越来越慢(本不该如此),但是恢复所花的时间确实会更短。要减少恢复时间,除了使用小的重做日志文件外,还可以使用其他的数据库参数。

3.7.2             归档重做日志

Oracle数据库可以采用两种模式运行:ARCHIVELOG模式和NOARCHIVELOG模式。这两种模式的区别只有一点,即Oracle重用重做日志文件时会发生什么情况。“会保留redo的一个副本吗?还是Oracle会将其重写,而永远失去原来的日志?”这是一个很重要的问题,下面就来回答。除非你保留了这个文件,否则无法从备份将数据恢复到当前的时间点。

假设你每周的星期六做一次备份。现在是星期五下午,已经生成了这一周的数百个重做日志,突然你的磁盘出问题了。如果没有以ARCHIVELOG模式运行,那么现在的选择只有:

q         删除与失败磁盘相关的表空间。只要一个表空间有该磁盘上的文件,就要删除这个表空间(包括表空间的内容)。如果影响到SYSTEM表空间(Oracle的数据字典),就不能用这个办法。

q         恢复上周六的数据,这一周的工作就白做了。

不论是哪种选择都不太好。这两种做法都意味着你会丢失数据。不过另一方面,如果之前以ARCHIVELOG模式运行,那么只需再找一个磁盘就行了。你要根据上周六的备份将受影响的文件恢复到这个磁盘上。最后,再对这些文件应用归档重做日志和(最终的)在线重做日志,实际上是以一种快进的方式重放整个星期的事务。这样一来,什么也不会丢失。数据会恢复到发生失败的那个时间点。

人们经常告诉我,他们的生产系统不需要ARCHIVELOG模式。在我的印象里,这样说的人没有一个说对的。我认为,如果系统不以ARCHIVELOG模式运行,那它根本就不能算是生产系统。未以ARCHIVELOG模式运行的数据库总有一天会丢失数据。这是在所难免的;如果你的数据库不以ARCHIVELOG模式运行,你肯定会丢失数据。

“我们在使用RAID-5,所以可以得到完全的保护”,这是一种很常见的托辞。我曾见过,由于制造方面的错误,RAID中的所有磁盘都“冻结”了,而且几乎是同时发生的。我也见过,有时硬件控制器会对数据文件带来破坏,所以他们只是在用RAID设备安全地保护已经被破坏的数据。另外,对于避免操作员错误(这也是丢失数据的一个最常见的原因),RAID也无能为力。

“在出现硬件或操作员错误之前,而且归档尚未受到影响,如果此时建立了备份,就能很好地恢复”。关键是,既然系统上的数据是有价值的,有什么理由不采用ARCHIVELOG模式呢?性能不能作为理由;适当配置的归档只会增加极少的开销甚至根本不增加开销。由于这一点,再加上另外一条:如果一个系统会“丢失数据”,那它再快也是没有用的,所以退一万步说,即使归档会增加100%的开销,我们也不得不做。如果可以把一个特性删除而没有任何重大损失,这个特性就叫做开销(overhead);开销就像是蛋糕上的糖霜,可以不要而不会影响蛋糕的美味。但归档不同,利用归档可以保住你的数据,确保数据不会丢失,这不是开销,而且正是DBA的主要任务!

只有测试或开发系统才应当采用NOARCHIVELOG模式执行。不要受人蛊惑在非ARCHIVELOG模式下运行。你花了很长时间开发你的应用,肯定希望人们相信你。如果把他们的数据丢失了,也会让他们对你的系统失去信心。

注意    有些情况下,大型的DW(数据仓库)以NOARCHIVELOG模式运行也是合适的,因为它可能适当地使用了READ ONLY(只读)表空间,而且会通过重新加载数据来完全重建受失败影响的所有READ WRITE(读写)表空间。

3.8   密码文件 

密码文件(password file)是一个可选的文件,允许远程SYSDBA或管理员访问数据库。

启动Oracle时,还没有数据库可以用来验证密码。在“本地”系统上启动Oracle时(也就是说,不在网络上,而是从数据库实例所在的机器启动),Oracle会利用操作系统来执行这种认证。

安装Oracle时,会要求完成安装的人指定管理员“组”。在UNIX/Linux上,这个组一般默认为DBA,在Windows上则默认为OSDBA。不过,也可以是平台上任何合法的组名。这个组很“特殊”,因为这个组中的任何用户都可以作为SYSDBA连接Oracle ,而无需指定用户名或密码。例如,在安装Oracle 10g Release 1时,我指定了一个ora 10g 组。ora 10g 组中的任何用户都无需用户名/密码就能连接:

[ora 10g @localhost ora 10g ]$ sqlplus / as sysdba

SQL*Plus: Release 10.1.0 .3.0 - Production on Sun Jan 2 20:13:04 2005

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

Connected to:

Oracle Database 10g Enterprise Edition Release 10.1.0 .3.0 - Production

With the Partitioning, OLAP and Data Mining options

 

SQL> show user

USER is "SYS"

这是可以的——我就成功地连接了Oracle,现在我能启动这个数据库,将其关闭,或者完成我想做的任何管理工作。不过,假设我想从另外一台机器通过网络完成这些操作,会怎么样呢?在这种情况下,我试图使用@tns-connect-string来连接。不过这会失败:

[ora 10g @localhost admin]$ sqlplus /@ora 10g _admin.localdomain as sysdba

SQL*Plus: Release 10.1.0 .3.0 - Production on Sun Jan 2 20:14:20 2005

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

ERROR:

ORA-01031: insufficient privileges

 

Enter user-name:

在网络上,对于SYSDBA的操作系统认证不再奏效,即使把很不安全的REMOTE_ OS_AUTHENT参数设置为TRUE也不例外。所以,操作系统认证不可行。如前所述,如果你想启动一个实例进行装载,并打开一个数据库,根据定义,在连接的另一端实际上“还没有数据库”,也无法从中查找认证的详细信息。这就是一个鸡生蛋还是蛋生鸡的问题。因此密码文件“应运而生”。密码文件保存了一个用户名和密码列表,这些用户名和密码分别对应于可以通过网络远程认证为SYSDBA的用户。Oracle必须使用这个文件来认证用户,而不是数据库中存储的正常密码列表。

下面校正这种情况。首先,我们要本地启动数据库,以便设置REMOTE_LOGIN_PASSWORDFILE。其默认值为NONE,这意味着没有密码文件;不存在“远程SYSDBA登录”。这个参数还有另外两个设置:SHARED(多个数据库可以使用同样的密码文件)和EXCLUSIVE(只有一个数据库使用一个给定的密码文件)。这里设置为EXCLUSIVE,因为我们只想对一个数据库使用这个密码文件(这也是一般用法):

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

System altered.

实例启动和运行时,这个设置不能动态改变,所以要想让它生效必须重启实例。下一步是使用命令行工具(UNIXWindows平台上)orapwd创建和填写这个初始的密码文件:

[ora 10g @localhost dbs]$ orapwd

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

在此:

file——密码文件名(必要)。

password——SYS 的密码(必要)。

entries——DBA和操作员的最大数目(可选)。

force——是否重写现有的文件(可选)。

等号(=)两边没有空格。

我们使用的命令为:

$ orapwd file=orapw$ORACLE_SID password=bar entries=20

对我来说,这样会创建一个名为orapwora 10g 的密码文件(我的ORACLE_SIDora 10g )。

这是大多数UNIX平台上密码文件的命名约定(有关各平台上密码文件的命名,详细内容请参见你的安装/操作系统管理员指南),这个文件位于$ORACLE_HOME/dbs目录中。在Windows上,文件名为PW%ORACLE_SID%.ora,在%ORACLE_HOME%/database目录中。

目前该文件中只有一个用户,也就是用户SYS,尽管数据库上还有其他SYSDBA账户,但它们还不在密码文件中。不过,基于以上设置,我们可以第一次作为SYSDBA通过网络连接Oracle

[ora 10g @localhost dbs]$ sqlplus sys/bar@ora 10g _admin.localdomain as sysdba

SQL*Plus: Release 10.1.0 .3.0 - Production on Sun Jan 2 20:49:15 2005

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

Connected to an idle instance.

SQL>

我们通过了认证,所以登录成功,现在可以使用SYSDBA账户成功地启动、关闭和远程管理这个数据库了。下面,再看另一个用户OPS$TKYTE,它已经是一个SYSDBA账户(已经授予SYSDBA),但是还不能远程连接:

[ora 10g @localhost dbs]$ sqlplus 'ops$tkyte/foo' as sysdba

SQL*Plus: Release 10.1.0 .3.0 - Production on Sun Jan 2 20:51:07 2005

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

Connected to:

Oracle Database 10g Enterprise Edition Release 10.1.0 .3.0 - Production

With the Partitioning, OLAP and Data Mining options

SQL> show user

USER is "SYS"

SQL> exit

[ora 10g @localhost dbs]$ sqlplus 'ops$tkyte/foo@ora 10g _admin.localdomain' as sysdba

SQL*Plus: Release 10.1.0 .3.0 - Production on Sun Jan 2 20:52:57 2005

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

ERROR:

ORA-01031: insufficient privileges

Enter user-name:

原因是,OPS$TKYTE还不在密码文件中。要把OPS$TKYTE放到密码文件中,需要重新对该账户授予SYSDBA

SQL> grant sysdba to ops$tkyte;

Grant succeeded.

 

Disconnected from Oracle Database 10g

Enterprise Edition Release 10.1.0 .3.0 - Production

With the Partitioning, OLAP and Data Mining options

[ora 10g @localhost dbs]$ sqlplus 'ops$tkyte/foo@ora 10g _admin.localdomain' as sysdba

SQL*Plus: Release 10.1.0 .3.0 - Production on Sun Jan 2 20:57:04 2005

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

Connected to:

Oracle Database 10g Enterprise Edition Release 10.1.0 .3.0 - Production

With the Partitioning, OLAP and Data Mining options

这样会在密码文件中创建一个条目,Oracle现在会保持密码“同步”。如果OPS$TKYTE修改了他的密码,原来的密码将无法完成远程SYSDBA连接,新密码才能启动SYSDBA连接:

SQL> alter user ops$tkyte identified by bar;

User altered.

[ora 10g @localhost dbs]$ sqlplus 'ops$tkyte/foo@ora 10g _admin.localdomain' as sysdba

SQL*Plus: Release 10.1.0 .3.0 - Production on Sun Jan 2 20:58:36 2005

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

ERROR:

ORA-01017: invalid username/password; logon denied

Enter user-name: ops$tkyte/bar@ora 10g _admin.localdomain as sysdba

Connected to:

Oracle Database 10g Enterprise Edition Release 10.1.0 .3.0 - Production

With the Partitioning, OLAP and Data Mining options

SQL> show user

USER is "SYS"

SQL>

对于其他不在密码文件中的SYSDBA用户,再重复同样的过程。

3.9   修改跟踪文件 

修改跟踪文件(change tracking file)是一个可选的文件,这是Oracle 10g 企业版中新增的。这个文件惟一的目的是跟踪自上一个增量备份以来哪些块已经修改。采用这种方式,恢复管理器(Recovery ManagerRMAN)工具就能只备份确实有变化的数据库块,而不必读取整个数据库。

Oracle 10g 之前的版本中,要完成增量备份,必须读取整个数据库文件,查找自上一次增量备份以来修改的块。所以,如果有一个1 TB的数据库,只在其中增加了500 MB的新数据(例如,数据仓库负载),增量备份就必须读取1 TB的数据,在其中找出要备份的500 MB新信息。所以,尽管增量备份存储的数据确实少得多,但它还是要读取整个数据库。

Oracle 10g 企业版中,就不是这样了。Oracle运行时,如果块被修改,Oracle可能会维护一个文件,告诉RMAN哪些块已经修改。创建这个修改跟踪文件的过程相当简单,只需通过ALTER DATABASE命令就可以完成:

ops$tkyte@ORA10GR1> alter database enable block change tracking

2 using file

3 '/home/ora10gr1/product/ 10.1.0 /oradata/ora10gr1/ORA10GR1/changed_blocks.bct';

Database altered.

警告    我在这本书里再三强调一点:要记住,不要轻易执行设置参数、修改数据库和产生重大改变的命令, 在你的“实际”系统上用这些命令之前一定要先进行测试。实际上,前面这个命令会导致数据库做更多工作。它会消耗资源。

要关闭和删除块修改跟踪文件,还要再用一次ALTER DATABASE命令:

ops$tkyte@ORA10GR1> alter database disable block change tracking;

Database altered.

 

ops$tkyte@ORA10GR1> !ls -l /home/ora10gr1/.../changed_blocks.bct

ls: /home/ora10gr1/.../changed_blocks.bct: No such file or directory

注意,这个命令实际上会清除块修改跟踪文件。它不只是禁用这个特性,而是连文件也一并删除了。可以采用ARCHIVELOGNOARCHIVELOG模式再次启用这个新的块修改跟踪特性。不过,要记住,NOARCHIVELOG模式的数据库中并不保留每天生成的重做日志,所以一旦介质(磁盘/设备)出现故障,所有修改都将无法恢复!NOARCHIVELOG模式的数据库总有一天会丢失数据。我们将在第9章更详细地讨论这两种数据库模式。

3.10      闪回日志文件 

闪回日志文件(flashback log file)简称为闪回日志(flashback log),这是Oracle 10g 中为支持FLASHBACK DATABASE命令而引入的,也是Oracle 10g 企业版的一个新特性。闪回日志包含已修改数据库块的“前映像”,可用于将数据库返回(恢复)到该时间点之前的状态。

3.10.1       闪回数据库

引入FLASHBACK DATABASE命令是为了加快原本很慢的时间点数据库恢复(point in time database recovery)过程。闪回可以取代完整的数据库恢复和使用归档日志完成的前滚,主要目的是加快从“意外状态”中恢复。例如,下面来看这样一种情况,如果DBA“意外地”删除了模式(schema),该如何恢复?他在本来要在测试环境中删除的数据库中删除了正确的模式。DBA立即意识到做错了,并且随即关闭了数据库。现在该怎么办?

在引入闪回数据库功能之前,可能只能这样做:

(1)   DBA要关闭数据库。

(2)   DBA(一般)要从磁带机恢复上一个完整的数据库备份。这通常是一个很长的过程。

(3)   DBA要恢复所生成的全部归档重做日志,因为系统上没有备份。

(4)   DBA要前滚数据库,并在出错的DROP USER命令之前的时间点停止。

(5)   要以RESETLOGS选项打开数据库。

这个过程很麻烦,步骤很多,通常要花费很长的时间(当然,这个期间任何人都无法访问数据库)。导致这种时间点恢复的原因有很多:如升级脚本错误,升级失败,有权限的某个人无意地发出了某个命令而导致时间点恢复(无意的错误,这可能是最常见的原因),或者是某个进程对一个大型数据库带来了数据完整性问题(同样,这可能也是意外;也许是进程运行了两次而不是一次,也可能是因为存在bug)。不论是什么原因,最终的结果都是很长时间的宕机。

Oracle 10g 企业版的恢复步骤如下,这里假设已经配置了闪回数据库功能:

(1) DBA关闭数据库。

(2) DBA启动并装载数据库,可以使用SCNOracle时钟或时间戳(墙上时钟时间)发出闪回数据库命令,时间可以精确到一两秒钟。

(3) DBARESETLOGS选项打开数据库。

要使用这个特性,数据库必须采用ARCHIVELOG模式,而且必须配置为支持FLASHBACK DATABASE命令。我的意思是,在你使用这个功能之前,必须先行配置。等到真正发生了破坏,再想启用这个功能就为时已晚了;使用时必须早做打算。

3.10.2       闪回恢复区

闪回恢复区(Flash Recovery Area)也是Oracle 10g 中的一个新概念。这么多年来(不止25年),Oracle中数据库备份的基本概念第一次有了变化。过去,数据库中备份和恢复的设计都围绕着一种顺序介质(如磁带设备)的概念。也就是说,总是认为随机存取设备(磁盘设备)太过昂贵,只是用来完成备份有些浪费,而应该使用相对廉价但存储量大的磁带设备。

不过,现如今完全可以用很少的价钱买到容量达TB的磁盘。实际上,到2007年,HP还打算推出磁盘容器达TB级的台式机。我还记得我的个人计算机上的第一块硬盘:在当时它的容量可是大得惊人:40 MB。实际上,我不得不把它分为两个逻辑盘,因为我所用的操作系统(当时是MS-DOS)无法识别超过32 MB的硬盘。在过去的20年间,情况已经发生了翻天覆地的变化。

Oracle 10g 中的闪回恢复区(Flash Recovery Area)是一个新位置,Oracle会在这里管理与数据库备份和恢复相关的多个文件。在这个区(area)中(这里“区”表示用于此目的的一个预留的磁盘区;例如一个目录),其中可以找到:

q         磁盘上数据文件的副本。

q         数据库的增量备份。

q         重做日志(归档重做日志)。

q         控制文件和控制文件的备份。

q         闪回日志。

Oracle利用这个新的闪回恢复区来管理这些文件,这样服务器就能知道磁盘上有什么,以及磁盘上没有什么(可能在别处的磁带上)。使用这些信息,数据库可以对被破坏的数据文件完成磁盘到磁盘的恢复操作,或者对数据库完成闪回(这是一种“倒带”操作),从而撤销一个不该发生的操作。例如,可以使用闪回数据库命令,将数据库放回到5分钟之前的状态(而不需要完整的数据库恢复和时间点恢复)。这样你就能“找回”无意删除的用户账户。

闪回恢复区更应算是一个“逻辑”概念。这是为本章讨论的各种文件类型所预留的一个区。使用闪回恢复区是可选的,没有必要非得使用,不过,如果你想使用诸如闪回数据库之类的高级特性,就必须用闪回恢复区存储信息。

3.11      DMP文件(EXP/IMP文件) 

导出工具(Export)和导入工具(Import)是年头已久的Oracle数据抽取和加载工具,很多个版本中都有这些工具。导出工具的任务是创建一个平台独立的DMP文件(转储文件),其中包含所有必要的元数据(CREATEALTER语句形式),可能还有数据本身,可以用于重新创建表、模式甚至整个数据库。导入工具的惟一作用就是读取这些DMP文件,执行其DDL语句,并加载它找到的所有数据。

DMP文件设计为向后兼容,这说明新版本可以读取老版本的DMP,并成功地处理。我听说有人导出过一个Oracle 5的数据库,并将其成功地导入到Oracle 10g 中(只是一个测试!)。所以导入工具可以读取老版本的DMP文件,并处理其中的数据。不过,大多数情况下反过来不成立:Oracle9i Release 1的导入工具进程不能(也不会)成功地读取Oracle9i Release 2 Oracle 10g Release 1创建的DMP。例如,我曾经从Oracle 10g Release 1 Oracle9i Release 2导出过一个简单的表。我试图在Oracle9i Release 1中使用这些DMP文件时,很快发现Oracle9i Release 1导入工具甚至不打算处理Oracle 10g Release 1DMP文件:

[tkyte@localhost tkyte]$ imp userid=/ full=y file= 10g .dmp

Import: Release 9.0.1 .0.0 - Production on Sun Jan 2 21:08:56 2005

(c) Copyright 2001 Oracle Corporation. All rights reserved.

Connected to: Oracle9i Enterprise Edition Release 9.0.1 .0.0 - Production

With the Partitioning option

JServer Release 9.0.1 .0.0 - Production

IMP-00010: not a valid export file, header failed verification

IMP-00000: Import terminated unsuccessfully

处理Oracle9i Release 2文件时,情况也好不到哪儿去:

[tkyte@localhost tkyte]$ imp userid=/ full=y file=9ir2.dmp

Import: Release 9.0.1 .0.0 - Production on Sun Jan 2 21:08:42 2005

(c) Copyright 2001 Oracle Corporation. All rights reserved.

Connected to: Oracle9i Enterprise Edition Release 9.0.1 .0.0 - Production

With the Partitioning option

JServer Release 9.0.1 .0.0 – Production

 

Export file created by EXPORT:V 09.02.00 via conventional path

import done in WE8ISO8859P1 character set and AL16UTF16 NCHAR character set

. importing OPS$TKYTE's objects into OPS$TKYTE

IMP-00017: following statement failed with ORACLE error 922:

"CREATE TABLE "T" ("X" NUMBER(*,0)) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRA"

"NS 255 STORAGE(INITIAL 65536 FREELISTS 1 FREELIST GROUPS 1) TABLESPACE "USE"

"RS" LOGGING NOCOMPRESS"

IMP-00003: ORACLE error 922 encountered

ORA-00922: missing or invalid option

Import terminated successfully with warnings.

9i Release 1试图读取文件,但它无法处理其中包含的DDLOracle9i Release 2中增加了一个新特性,称为表压缩(table compression)。因此,这个版本的导出工具开始对每条CREATE TABLE语句增加一个NOCOMPRESSCOMPRESS关键字。Oracle9i Release 2DDLOracle9i Release 1中无法执行。

不过,如果对Oracle9i Release 2 Oracle 10g Release 1使用Oracle9i Release 1 导出工具,总会得到一个有效的DMP文件,并可以成功地导入到Oracle9i Release 1中。所以,对于DMP文件的规则是:创建DMP文件的Export版本必须小于或等于使用该DMP文件的Import的版本。要将数据导入Oracle9i Release 1中,必须使用Oracle9i Release 1的导出工具(或者也可以使用一个8iExport进程;创建DMP文件的Export版本必须小于或等于Oracle9i Release 1)。

这些DMP文件是平台独立的,所以可以安全地用任何平台的导出工具创建DMP文件,然后转换到另一个平台,再导入这个DMP文件(只要Oracle版本允许)。不过,对于Windows和文件的FTP传输有一点警告,Windows会默认地把DMP文件当成是一个“文本”文件,并把换行符(UNIX上为行末标记)转换为回车/换行对,这就会完全破坏DMP文件。在Windows中通过FTP传输DMP文件时,要确保所执行的是二进制传输。如果导入不成功,请检查源文件大小和目标文件大小是否一样。这种问题常常导致令人痛苦的异常中止,而不得不重传文件,这种情况发生过多少次我简直都记不清了。

DMP文件是二进制文件,这说明你不能编辑这些文件来进行修改。可以从中抽取大量信息(CREATE DDL),但是不能在文本编辑器(或者实际上任何类型的编辑器)中编辑它们。在第一版的Expert One-on-One Oracle中(你手上的是第二版,本书配套光盘提供了第一版的电子文档),我花了大量篇幅讨论导入和导出工具,并介绍了如何使用DMP文件。随着这些工具越来越失宠,取而代之的是更为灵活的数据泵工具,所以要想全面地了解如何管理导入和导出工具、如何从中抽取数据以及如何使用这些工具,请参考第一版的电子文档。

3.12      数据泵文件 

Oracle 10g 中至少有两个工具使用数据泵(data pump)文件格式。外部表(external table)可以加载和卸载数据泵格式的数据,新的导入/导出工具IMPDPEXPDP 使用这种文件格式的方式与IMPEXP使用DMP文件格式的方式完全一样。

注意   数据泵格式只在Oracle 10g Release 1及以后版本中可用,Oracle9i release中没有也不能使用它。

前面提到过对DMP文件的警告,这些警告同样适用于数据泵文件。它们都是跨平台(可移植)的二进制文件,包含有元数据(并非存储为CREATE/ALTER语句,而是作为XML存储),可能还包含数据。数据泵文件使用XML作为元数据表示结构,这一点对你和我这些最终用户来说非常重要。IMPDPEXPDP有一些复杂的过滤和转换功能,这些在老版本的IMP/EXP 工具中是没有的。从某种程度上讲,这就归功于使用了XML,另外还因为CREATE TABLE语句并非存储为CREATE TABLE,而是存储为一个有标记的文档。这样就能很容易地实现一些请求,如“请把表空间FOO的所有引用替换为表空间BAR”。DMP中元数据存储为CREATE/ALTER语句,导入工具在执行SQL语句之前实际上必须解析每一条SQL语句,才能完成这个工作(做得并不漂亮)。与之不同,IMPDP只需应用一个简单的XML转换就能达到同样的目的,FOO(指一个TABLESPACE)会转换为<TABLESPACE>FOO</TABLESPACE>标记或另外某种表示。

由于使用了XML,这使得EXPDPIMPDP工具的功能相对于原来的EXPIMP工具来说有了大幅的提升。在第15章,我们将更深入地介绍这些工具。不过,在此之前,先来看看如何使用数据泵格式快速地从数据库A抽取数据,并移至数据库B。这里我们将使用一个“反过来的外部表”。

外部表(external table)最早在Oracle9i Release 1中引入,利用外部表,我们能像读取数据库表一样读取平面文件(无格式的文本文件),完全可以用SQL来处理外部表。外部表是只读的,设计为从外部向Oracle提供数据。Oracle 10g Release 1及以上版本中的外部表还可以走另外一条路:用于以数据泵格式从数据库获取数据,以便将数据移至另一台机器(另一个平台)。要完成这个练习,首先需要一个DIRECTORY对象,告诉Oracle卸载的位置:

ops$tkyte@ORA 10G > create or replace directory tmp as '/tmp'

2 /

Directory created.

接下来,从ALL_OBJECTS视图卸载数据。数据可以来自任意查询,涉及我们想要的所有表或SQL构造:

ops$tkyte@ORA 10G > create table all_objects_unload

2          organization external

3          ( type oracle_datapump

4           default directory TMP

5           location( 'allobjects.dat' )

6          )

7          as

8          select * from all_objects

9          /

Table created.

从字面上可以很清楚地看出其含义:在/tmp中有一个名为allobjects.dat的文件,其中包含查询select * from all_objects的内容。可以看一下这个信息:

ops$tkyte@ORA 10G > !head /tmp/allobjects.dat

..........Linuxi386/Linux-2.0.34-8.1.0WE8ISO8859P1..........

<?xml version="1.0"?>

         <ROWSET>

                  <ROW>

                           <STRMTABLE_T>

                           <VERS_MAJOR>1</VERS_MAJOR>

                           <VERS_MINOR>0 </VERS_MINOR>

                           <VERS_DPAPI>3</VERS_DPAPI>

                           <ENDIANNESS>0</ENDIANNESS>

                           <CHARSET>WE8ISO8859P1</CHARSET>

这只是文件的开头,即最前面的部分;二进制数据表示为……(如果查看这个数据时你的终端发出“嘟嘟”声,不要奇怪)。下面使用二进制FTP传输(DMP文件的警告同样适用!),将这个allobject.dat文件移至一个Windows XP服务器,并创建一个目录对象与之对应:

tkyte@ORA 10G > create or replace directory TMP as 'c:/temp/'

2 /

Directory created.

然后创建一个表指向这个外部表:

tkyte@ORA 10G > create table t

2          ( OWNER VARCHAR2(30),

3           OBJECT_NAME VARCHAR2(30),

4           SUBOBJECT_NAME VARCHAR2(30),

5           OBJECT_ID NUMBER,

6           DATA_OBJECT_ID NUMBER,

7           OBJECT_TYPE VARCHAR2(19),

8           CREATED DATE,

9           LAST_DDL_TIME DATE,

10         TIMESTAMP VARCHAR2(19),

11         STATUS VARCHAR2(7),

12         TEMPORARY VARCHAR2(1),

13         GENERATED VARCHAR2(1),

14         SECONDARY VARCHAR2(1)

15 )

16 organization external

17         ( type oracle_datapump

18         default directory TMP

19         location( 'allobjects.dat' )

20 )

21 /

Table created.

现在就能查询从另一个数据库卸载的数据了:

tkyte@ORA 10G > select count(*) from t;

COUNT(*)

----------

48018

这就是数据泵文件格式的强大之处:如果需要,它能立即通过一个“隐秘的网”将数据从一个系统传输到另一个系统。想想看,有了数据泵,下一次测试时,周末你就能把一部分数据带回家去工作了。

有一点不太明显:这两个数据库的字符集不同。如果你注意以上输出的开头部分,可以发现Linux数据库WE8ISO8859P1的字符集已经编码写入到文件中。我的Windows服务器则有:

tkyte@ORA 10G > select *

2 from nls_database_parameters

3 where parameter = 'NLS_CHARACTERSET';

PARAMETER                       VALUE

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

NLS_CHARACTERSET     WE8MSWIN1252

归功于数据泵文件格式,Oracle现在能识别不同的字符集,并能加以处理。字符集转换会根据需要动态地完成,使得各个数据库表示中的数据“正确”。

我们还是会在第15章再详细讨论数据泵文件格式,不过通过这一节的介绍,你应该对数据泵文件格式是什么以及这个文件中可能包含什么有一定的认识了。 

3.13      平面文件 

自从有了电子数据处理,就有了平面文件(flat file)。我们每天都会看到平面文件。前面讨论的警告日志就是一个平面文件。

我在Web上看到有关“平面文件”的以下定义,觉得这些定义实在太绕了:

平面文件是去除了所有特定应用(程序)格式的电子记录,从而使数据元素可以迁移到其他的应用上进行处理。这种去除电子数据格式的模式可以避免因为硬件和专有软件的过时而导致数据丢失。

平面文件是一种计算机文件,所有信息都在一个信号字符串中。

实际上,平面文件只是这样一个文件,其中每一“行”都是一个“记录”,而且每行都有一些定界的文本,通常用逗号或管道符号(竖线)分隔。通过使用遗留的数据加载工具SQLLDR或外部表,Oracle可以很容易地读取平面文件,实际上,我会在第15章详细讨论这个内容(还会在第10章谈到外部表)。不过,Oracle生成平面文件可就不那么容易了,不管由于什么原因,确实没有一个简单的命令行工具能把信息导出到一个平面文件中。诸如HTML DB和企业管理器之类的工具有助于完成这个过程,但是并没有一个官方的命令行工具可以轻松地在脚本中用来完成这个操作。

正是出于这个原因,所以我决定在这一章对平面文件说两句,我提议能有一些生成简单平面文件的工具。多年来,为此我开发过3种方法,每种方法都各有特点。第一种方法是使用PL/SQLUTL_FILE(利用动态SQL)来完成任务。如果数据量不大(几百或几千行),这个工具则有足够的灵活性,速度也不错。不过,它必须在数据库服务器主机上创建文件,但有时我们并不想在数据库服务器上创建文件。因此,我又开发了一个 SQL*Plus实用程序,可以在运行SQL*Plus的机器上创建平面文件。由于SQL*Plus可以连接网络上任何位置的Oracle服务器,所以能从网络上的任何数据库把任何数据卸载到一个平面文件中。最后,如果速度要求很高,那么非C莫属。为此,我还开发了一个Pro*C命令行卸载工具来生成平面文件。这些工具都可以从http://asktom.oracle.com/~tkyte/flat/index.html免费得到,另外我还会在这里提供为了把数据卸载到平面文件而开发的新工具。

3.14      小结 

在这一章中,我们分析了Oracle数据库使用的各种重要的文件类型,从底层的参数文件(如果没有参数文件,甚至无法启动数据库)到所有重要的重做日志和数据文件。我们分析了Oracle的存储结构,从表空间到段,再到区段,最后是数据库块(这是最小的存储单位)。我们还简要介绍了检查点在数据库中如何工作,并提前了解了Oracle的一些物理进程或线程的工作。

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值