数据库由一个或多个表空间构成。
表空间
(
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 Disks,RAID)之类的磁盘技术,你可能会发现,一个文件不仅在一个磁盘上不连续,还有可能跨多个物理磁盘。每个段都至少有一个区段,有些对象可能还需要至少两个区段(回滚段就至少需要两个区段)。如果一个对象超出了其初始区段,就会请求再为它分配另一个区段。第二个区段不一定就在磁盘上第一个区段旁边,甚至有可能不在第一个区段所在的文件中分配。第二个区段可能与第一个区段相距甚远,但是区段内的空间总是文件中的一个逻辑连续空间。区段的大小可能不同,可以是一个Oracle数据块,也可以大到2 GB。
3. 块
区段又进一步由块组成。
块
(
block
)
是
Oracle
中最小的空间分配单位。数据行、索引条目或临时排序结果就存储在块中。通常
Oracle
从磁盘读写的就是块。
Oracle
中块的常见大小有
4
种:
2 KB
、
4 KB
、
8 KB
或
16 KB
(尽管在某些情况下
32 KB
也是允许的;但是操作系统可能对最大大小有限制)。
注意 有一点可能很多人都不知道:数据库的默认块大小不必是2的幂。2的幂只是一个常用的惯例。实际上,你完全可以创建块大小为5 KB、7 KB或
n KB的数据库,这里
n介于2~32 KB之间。不过,我还是建议你在实际中不要考虑这样做,块大小还是用2 KB、4 KB、8 KB或16 KB比较好。
段、区段和数据块之间的关系如
图3-1所示。
一个段由一个或多个区段组成,区段则由连续分配的一些块组成。从Oracle9
i Release 1起,数据库中最多可以有6种不同的块大小(block size)。

图3-1 段、区段和数据块
注意 之所以引入这个特性,即一个数据库中允许有多种块大小,目的是为了可以在更多的情况下使用可传输的表空间。如果能传输表空间,DBA就能从一个数据库移动或复制格式化的数据文件,把它放在另一个数据库中,例如,可以从一个联机事务处理(Online Transaction Processing,OLTP)数据库中把所有表和索引复制到一个数据仓库(Data Warehouse,DW)中。不过,在许多情况下,OLTP数据库使用的块大小可能很小,如2 KB或4 KB,而DW使用的块大小可能很大(8 KB或16 KB)。如果一个数据库中不支持多种块大小,就无法传输这些信息。有多种块大小的表空间主要用于传输表空间,一般没有其他用途。
数据库还有一个默认的块大小,即执行
CREATE DATABASE命令时初始化文件中指定的大小。
SYSTEM表空间总是使用这个默认块大小,不过你完全可以按非默认块大小(2 KB、4 KB、8 KB或16 KB)创建其他表空间,如果操作系统允许,还可以使用32 KB的块大小。当且仅当创建数据库时指定了一个非标准的块大小(不是2的幂)时,才会有6种不同的块大小。因此,在实际中,数据库最多有5种不同的块大小:默认大小和另外4种非默认的块大小。
在所有给定的表空间内部,
块大小都是一致的,这说明,一个表空间中的所有块大小都相同。对于一个多段对象,如一个包含LOB
列的表,可能每个段在不同的表空间中,而这些表空间分别有不同的块大小,但是任何给定段(包含在表空间中)都由相同大小的块组成。无论大小如何,所有块格式都一样,如图3-2所示。2 块结构

图3-
块首部(block header)包含块类型的有关信息(表块、索引块等)、块上发生的活动事务和过去事务的相关信息(仅事务管理的块有此信息,例如临时排序块就没有事务信息),以及块在磁盘上的地址(位置)。块中接下来两部分是表目录和行目录,最常见的数据库块中(即堆组织表的数据块)都有这两部分。第10章将更详细地介绍数据库表类型,不过,现在知道大多数表都是这种类型就足够了。如果有
表目录(table directory),则其中会包含把行存储在这个块上的表的有关信息(可能一个块上存储了多个表的数据)。
行目录(row directory)包含块中行的描述信息。这是一个指针数组,指向块中数据部分中的行。块中的这3部分统称为
块开销(block overhead),这部分空间并不用于存放数据,而是由Oracle用来管理块本身。块中余下的两部分就很清楚了:块上可能有一个
空闲空间(free space),通常还会有一个目前已经存放数据的
已用空间(used space)。
从以上介绍可以知道,段由区段组成,区段由块组成,对段有了大致的了解后,下面再来更深入地分析表空间,然后说明文件在这个存储层次体系中的位置。
4. 表空间
前面已经提到,表空间是一个容器,其中包含有段。每个段都只属于一个表空间。一个表空间中可能有多个段。一个给定段的所有区段都在与段相关联的表空间中。段绝对不会跨越表空间边界。表空间本身可以有一个或多个相关的数据文件。表空间中给定段的一个区段完全包含在一个数据文件中。不过,段可以有来自多个不同数据文件的区段。表空间如图3-3所示。3 这个表空间包含两个数据文件、3个段和4个区段

图3-
图3-3显示了一个名为
USER_DATA的表空间。其中包括两个数据文件:
user_data01和
user_data02。并分配了3个段:
T1、
T2和
I1(可能是两个表和一个索引)。这个表空间中分配了4个区段,每个区段表示为逻辑上连续分配的一组数据库块。段
T1包括两个区段,分别在不同的文件中。段
T2和
I1都各有一个区段。如果这个表空间需要更多的空间,可以调整已经分配给表空间的数据文件的大小,或者可以再增加第三个数据文件。
表空间是Oracle中的逻辑存储容器。作为开发人员,我们会在表空间中创建段,而绝对不会深入到原始的“文件级”。我们可不希望在一个特定的文件中分配区段(当然这也是可以的,但我们一般都不会这么做)。相反,我们会在表空间中创建对象,余下的工作都由Oracle负责。如果将来某个时刻DBA决定在磁盘上移动数据文件,从而使I/O分布得更均匀,这对我们来说没有任何关系,它根本不会影响我们的处理。
5. 存储层次体系小结
总结一下,Oracle中的存储层次体系如下:
(1)
数据库由一个或多个表空间组成。
(2)
表空间由一个或多个数据文件组成。这些文件可以是文件系统中的cooked文件、原始分区、ASM管理的数据库文件,或集群文件系统上的文件。表空间包含段。
(3)
段(
TABLE、
INDEX等)由一个或多个区段组成。段在表空间中,但是可以包含这个表空间中多个数据文件中的数据。
(4)
区段是磁盘上一组逻辑连续的块。区段只在一个表空间中,而且总是在该表空间内的一个文件中。
(5)
块是数据库中最小的分配单位,也是数据库使用的最小I/O单位。