PARTIV-Oracle数据库存储结构-逻辑存储结构
12.逻辑存储结构
12.1. 逻辑存储结构简介
Oracle数据库逻辑存储由数据块、区、段和表空间构成,各存储单位的关系如图12-1物理和逻辑存储的实体-关系图所示(乌鸦脚符号表示一对多关系)。在物理层面,数据存储在磁盘上的数据文件中,数据文件中的数据存储在操作系统块中。
12.1.1. 逻辑存储层次结构
图12-2显示了表空间内数据块、区间和段之间的关系。在这个例子中,一个段有两个区,存储在不同的数据文件中。
Oracle存储数据的最小单位是数据块,一个逻辑数据块对应于物理磁盘空间的特定字节数,例如,2KB。一组逻辑上连续的数据块组成了区,用来存储特定类型的信息。在图12-2中,24KB的区包含12个数据块,而72KB的区间包含36个数据块。一组区构成了段从而存储特定的数据库对象(如表)例如,员工表的数据存储在其自己的数据段中,而员工的每个索引都存储在其自己的索引段中。每个消耗存储空间的数据库对象都由一个单独的段组成。每个段都属于且只属于一个表空间。因此,一个段的所有区都存储在同一个表空间中。在表空间内,一个段里面的区的数据可以来自多个数据文件,如图12-2所示。一个段的一个区间可能存储在users01.dbf中,而另一个区间可能存储在users02.dbf中。单个区间永远不能跨越数据文件。
12.1.2. 逻辑空间管理
Oracle的逻辑空间管理指的是跟踪和分配表空间中的区的管理方式。当数据库对象需要一个区时,数据库必须有一种方法来查找和提供它。类似地,当对象不再需要一个区间时,数据库必须有一种方法来使空闲区间可用。Oracle数据库根据您创建的类型在表空间内管理空间。您可以创建以下类型的表空间:
■ 本地管理表空间(默认)
数据库使用表空间本身的位图来管理区。因此,本地管理表空间有一部分被留作位图。在表空间内,数据库可以使用自动段空间管理(ASSM)或手动段空间管理(MSSM)来管理段。
■ 字典管理表空间
数据库使用数据字典来管理区。
图12-3显示了表空间中逻辑空间管理的替代方案。
12.1.2.1. 本地管理表空间
本地管理表空间在数据文件头部维护一个位图,以跟踪数据文件主体中的空闲和已使用空间。每个位对应一组数据块。当空间被分配或释放时,Oracle数据库会更改位图的值,以反映数据块的新状态。
以下图形是位图管理存储的概念性表示。头部中的1表示已使用空间,而0表示空闲空间。
本地管理表空间具有以下优点:
■ 避免使用数据字典来管理区间
如果在字典管理的表空间中,消耗或释放区中的空间会导致另一个在数据字典表或回滚段中的空间消耗或释方的操作递归的产生。
■ 自动跟踪相邻的空闲空间
通过这种方式,数据库消除了合并空闲区间的需要。
■ 自动确定本地管理区的大小
或者说,本地管理表空间中的所有区可以具有相同的大小,并覆盖对象存储的选项。
注意:Oracle强烈建议使用自动段空间管理的本地管理表空间。
段空间管理 是一种继承自包含特定段的表空间的属性。在本地管理表空间内,数据库可以自动或手动管理段。例如,users表空间中的段可以自动管理,而tools表空间中的段则手动管理。
自动段空间管理 ASSM方法使用位图来管理空间。位图提供以下优点:
■ 简化管理 ASSM避免了手动确定许多存储参数的正确设置的需要。只有一个关键的SQL参数控制空间分配:PCTFREE。此参数指定了为未来更新保留的数据块中的空间百分比。
■ 提高并发性
多个事务可以搜索单独的空闲数据块列表,从而减少争用和等待。对于许多标准工作负载,使用ASSM的应用程序性能比使用MSSM的经过良好调整的应用程序性能更好。
■ 在Oracle实时应用集群(Oracle RAC)环境中空间对实例的动态亲和性
ASSM更有效,是永久性本地管理表空间的默认设置。
注意:本章假设在所有关于逻辑存储空间的讨论中都使用ASSM。
手动段空间管理 传统的MSSM方法使用一个名为空闲列表的链表来管理段中的空闲空间。对于有空闲空间的数据库对象,空闲列表跟踪高水位线(HWM)以下的块,这是已使用和尚未使用的段空间之间的分界线。随着块的使用,数据库根据需要将块添加到或从空闲列表中移除。除了PCTFREE,MSSM还需要您使用SQL参数如PCTUSED、FREELISTS和FREELIST GROUPS来控制空间分配。PCTUSED设置了数据库将其添加到空闲列表的当前使用块中必须存在的空闲空间百分比。例如,如果您在CREATE TABLE语句中将PCTUSED设置为40,则意味着如果一个数据块中至少有40%的空间未被使用,该数据块就会被列入空闲列表。
作为示例,假设您向表中插入一行。数据库检查表的空闲列表以寻找第一个可用块。如果行不能放入块中,并且如果块中已使用的空间大于或等于PCTUSED,则数据库将该块从列表中移除并寻找另一个块。如果您从块中删除行,则数据库会检查块中现在已使用的空间是否小于PCTUSED。如果是这样,那么数据库将该块放置在空闲列表的开头。
一个对象可以有多个空闲列表。通过这种方式,多个会话对表执行DML操作时可以使用不同的列表,这可以减少争用。每个数据库会话在其会话期间只使用一个空闲列表。如图12-4所示,可以创建一个具有一个或多个空闲列表组的对象,空闲列表组是空闲列表的集合。每个组都有一个主空闲列表,管理组中的各个进程空闲列表。空闲列表的空间开销,特别是对于空闲列表组,可能会很大。
手动管理段空间可能会很复杂。您必须调整PCTFREE和PCTUSED以减少行迁移并避免浪费空间。例如,如果段中每个已使用的块都只有一半满了,而PCTUSED是40,那么数据库不允许在这些块中的任何一个中插入新行。由于调整空间分配参数的困难,Oracle强烈推荐使用ASSM。在ASSM中,PCTFREE决定了是否可以将新行插入到块中,但它不使用空闲列表并忽略PCTUSED。
12.1.2.2. 字典管理表空间
字典管理表空间使用数据字典来管理其区。Oracle数据库在为区分配或释放重用时,会更新数据字典中的表。例如,当一个表需要一个区时,数据库会查询数据字典表并搜索空闲区。如果数据库找到空,那么它会修改一个数据字典表并插入另一行。通过这种方式,数据库通过修改和移动数据来管理空间。
数据库在后台执行的SQL以获取数据库对象空间是递归SQL。频繁使用递归SQL可能会对性能产生负面影响,因为对数据字典的更新必须序列化。本地管理表空间(默认设置)避免了这种性能问题。
12.2. 数据块概述
Oracle数据库以称为数据块的单位管理数据库数据文件中的逻辑存储空间,数据块也称为Oracle块或页面。数据块是数据库I/O的最小单位。
12.2.1. 数据块和操作系统块
在物理层面,数据库的数据存储在由操作系统块组成的磁盘文件中。操作系统块是操作系统可以读取或写入的最小数据单位。相比之下,Oracle块是一个逻辑存储结构,其大小和结构对操作系统是不可见的。图12-5显示操作系统块的大小可能与数据块不同。数据库请求数据是以数据块的倍数进行的,而不是操作系统块。
当数据库请求一个数据块时,操作系统将此操作转换成对永久存储中数据的请求。数据块与操作系统块之间的逻辑分离有以下含义:
■ 应用程序不需要确定磁盘上数据的物理地址。
■ 数据库数据可以在多个物理磁盘上进行条带化或镜像。
12.2.1.1. 数据库块大小
每个数据库都有一个数据库块大小。在创建数据库时,DB_BLOCK_SIZE初始化参数设置了数据库的数据块大小。该大小为SYSTEM和SYSAUX表空间设置,并作为所有其他表空间的默认值。除非重新创建数据库,否则无法更改数据库块大小。如果未设置DB_BLOCK_SIZE,则默认数据块大小取决于操作系统。数据库的标准数据块大小为4KB或8KB。如果数据块大小与操作系统块大小不同,则数据块大小必须是操作系统块大小的倍数。
12.2.1.2. 表空间块大小
可以创建与DB_BLOCK_SIZE设置不同块大小的个别表空间。非标准块大小在将可传输表空间移动到不同平台时很有用。
12.2.2. 数据块格式
每个数据块都有一个格式或内部结构,使数据库能够跟踪数据块中的数据和空闲空间。这种格式无论是包含表、索引还是表簇数据的数据块都是相似的。图12-6显示了一个未压缩数据块的格式。
12.2.2.1. 数据块开销(Data Block Overhead)
Oracle数据库使用数据块开销来管理数据块本身。数据块开销不可用于存储用户数据。如图12-6所示,数据块开销包括以下部分:
■ 数据块头部
这部分包含有关数据块的一般信息,包括磁盘地址和段类型。对于事务管理的数据块,数据块头部包含活动和历史事务信息。
对于每个更新数据块的事务来说,事务条目是需要的。Oracle数据库最初在数据块头部为事务条目预留空间。在分配给支持事务性更改的段的数据块中,当头部空间耗尽时,空闲空间也可以保存事务条目,事务条目所需的空间依赖于操作系统。然而,在大多数操作系统中,事务条目大约需要23字节。
■ 表目录
对于堆组织表,此目录包含存储在此数据块中的行的元数据。多个表可以在同一个数据块中存储行。
■ 行目录
对于堆组织表,此目录描述数据块数据部分中行的位置。在行目录分配空间后,数据库在行删除后不会回收此空间。因此,一个当前为空但以前有50行的数据块继续为行目录分配100字节。数据库仅在新行插入数据块时重用此空间。
数据块开销的某些部分大小是固定的,但总大小是可变的。平均来说,数据块开销总计为84到107字节。
12.2.2.2. 行格式(Row Format)
数据块的行数据部分包含实际数据,例如表行或索引键条目。就像每个数据块都有一个内部格式一样,每一行都有一个行格式,使数据库能够跟踪行中的数据。
Oracle 数据库将行存储为可变长度记录。一行包含在一个或多个行片段中。每个行片段都有一个行头部和列数据。
图12-7显示了一行的格式。
行头部(Row Header) Oracle 数据库使用行头部来管理存储在数据块中的行片段。行头部包含以下信息:
■ 行片段中的列
■ 位于其他数据块中的行片段
如果整行可以插入到单个数据块中,那么Oracle 数据库将该行存储为一个行片段。然而,如果所有行数据无法插入到单个块中,或者更新导致现有行超出其块大小,则数据库将行存储在多个行片段中(参见第12-16页的“链式和迁移行”)。通常,一个数据块只包含每行的一个行片段。
表簇的簇键(参见第2-22页的“表簇概述”)
完全包含在一个块中的行至少有3字节的行头部。
列数据(Column Data) 在行头部之后,列数据部分存储行中的实际数据。行片段通常按CREATE TABLE语句中列出的顺序存储列,但这种顺序并不保证。例如,类型为LONG的列是最后创建的。
如图12-7所示,对于行片段中的每个列,Oracle 数据库分别存储列长度和数据。所需的空间取决于数据类型。如果列的数据类型是可变长度的,那么随着数据的更新,存储一个值所需的空间可以增长和缩小。
每个行在数据块头部的行目录中都有一个槽位。该槽位指向行的开始位置。
ROWID格式(Rowid Format)Oracle数据库使用行 ID(rowid)来唯一标识一行。在内部,行 ID 是一个结构,包含数据库访问一行所需的信息。行ID在物理上并不存储在数据库中,而是从存储数据的文件和块中推断出来的。扩展行ID包括一个数据对象编号。这种行 ID 类型使用每个行的物理地址的基于64的编码。编码字符是 A-Z、a-z、0-9、+ 和 /。
示例12-1查询ROWID伪列,以显示员工表中员工100的行的扩展行ID。
Example 12–1 ROWID Pseudocolumn
SQL> SELECT ROWID FROM employees WHERE employee_id = 100;
ROWID
-----------------
AAAPecAAFAAAABSAAA
图12-8说明了扩展行 ID 的格式。
扩展行 ID 以四部分格式显示,OOOOOOFFFBBBBBBRRR,格式分为以下组件:
■ OOOOOO
数据对象编号标识段(示例12-1中的数据对象AAAPec)。每个数据库段都被分配一个数据对象编号。在同一段中的模式对象,如表簇,具有相同的数据对象编号。
■ FFF
表空间相对数据文件编号标识包含行的数据文件(示例12-1中的文件AAF)。
■ BBBBBB
数据块编号标识包含行的数据块(示例12-1中的块AAAABS)。块编号是相对于它们的数据文件,而不是它们的表空间。因此,具有相同块编号的两行可能位于同一表空间的不同数据文件中。
■ RRR
行编号标识数据块中的行(示例12-1中的行AAA)。
在为行片段分配行 ID 后,在特殊情况下行 ID 可能会更改。例如,如果启用了行移动,则由于分区键更新、Flashback Table操作、收缩表操作等原因,行 ID 可能会更改。如果禁用了行移动,则在行被导出并使用Oracle数据库实用程序导入时,行ID可能会更改。
注意:在内部,数据库执行行移动就好像行被物理删除并重新插入一样。然而,行移动被视为更新,这对触发器有影响。
12.2.3. 数据块压缩
数据库可以使用表压缩来消除数据块中的重复值(参见第2-19页的“表压缩”)。本节描述了使用压缩的数据块的格式。使用基本和高级行压缩的数据块的格式基本上与未压缩的数据块相同。不同之处在于,块的开头有一个符号表,用于存储行和列的重复值。数据库用符号表的简短引用替换这些值的出现。
假设示例12-2中的行存储在七列销售表的数据块中。
Example 12–2 Rows in sales Table
2190,13770,25-NOV-00,S,9999,23,161
2225,15720,28-NOV-00,S,9999,25,1450
34005,120760,29-NOV-00,P,9999,44,2376
9425,4750,29-NOV-00,I,9999,11,979
1675,46750,29-NOV-00,S,9999,19,1121
当基本或高级行压缩应用于此表时,数据库用符号引用替换重复值。示例12-3是对压缩的概念性表示,其中符号*代替29-NOV-00,%代替9999。
Example 12–3 OLTP Compressed Rows in sales Table
2190,13770,25-NOV-00,S,%,23,161
2225,15720,28-NOV-00,S,%,25,1450
34005,120760,*,P,%,44,2376
9425,4750,*,I,%,11,979
1675,46750,*,S,%,19,1121
表12-1概念性地表示了将符号映射到值的符号表。
12.2.4. 数据块上的空间管理
当数据库从下往上填充数据块时,行数据和块头部之间的空闲空间量会减少。在更新过程中,这种空闲空间也可能缩小,例如,当将尾部空值更改为非空值时。数据库管理数据块中的空闲空间,以优化性能并避免浪费空间。
注意:本节假设使用自动段空间管理。
12.2.4.1. 数据块中的空闲空间百分比
存储参数 PCTFREE 对数据库如何管理空闲空间至关重要。这个 SQL 参数设置了数据块中保留为更新现有行的空闲空间的最小百分比。因此,PCTFREE 对于防止行迁移和避免浪费空间非常重要。
例如,假设您创建了一个表,它只需要偶尔更新,而且大多数更新不会增加现有数据的大小。您可以在 CREATE TABLE 语句中指定 PCTFREE 参数,如下所示:
CREATE TABLE test_table (n NUMBER) PCTFREE 20;
图12-9显示了20的 PCTFREE 设置如何影响空间管理。数据库随着时间的推移向块中添加行,导致行数据向上增长,靠近块头部,而块头部本身则向下扩展,靠近行数据。PCTFREE 设置确保至少有20%的数据块是空闲的。例如,数据库防止 INSERT 语句填满数据块,使得行数据和头部总共占用数据块空间的90%,仅留下10%的空闲空间。
注意:这一讨论不适用于 LOB 数据类型,它们不使用 PCTFREE 存储参数或空闲列表。请参阅第19-12页的“LOB概述”。
12.2.4.2. 数据块中的空闲空间优化
虽然空闲空间的百分比不能低于 PCTFREE 设置的值,但空闲空间的数量可以更多。例如,PCTFREE 设置为20%可以防止空闲空间的总量降至数据块的5%,但允许数据块有50%的空闲空间。以下SQL语句可以增加空闲空间:
■ DELETE语句
■ 更新现有值到更小的值,或增加现有值并迫使行迁移的UPDATE语句
■ 在使用OLTP压缩的表上执行的INSERT语句
如果插入操作用数据填满了数据块,数据库会调用块压缩,这可能导致数据块有更多的空闲空间。
释放的空间在以下条件下可用于INSERT语句:
■ 如果INSERT语句与释放空间的语句处于同一事务中,并且紧随释放空间的语句之后,则该语句可以使用该空间。
■ 如果INSERT语句与释放空间的语句处于不同的事务中(可能是由另一个用户运行的),则该语句只有在其他事务提交后,并且只有在需要空间时才能使用释放的空间。
合并碎片空间。释放的空间可能与数据块中主要空闲区域连续,也可能不连续,如图12-10所示。不连续的空闲空间被称为碎片空间。
Oracle 数据库只有在以下条件全部满足时,才会自动且透明地合并数据块中的空闲空间:
■ 当一个 INSERT 或 UPDATE 语句尝试使用一个包含足够空闲空间来容纳新行片段的数据块时。
■ 空闲空间是碎片化的,以至于行片段无法插入到数据块的一个连续区域内。
合并后,空闲空间的数量与操作前相同,但现在空间是连续的。图12-11显示了一个合并空间后的数据块。
Oracle 数据库仅在上述情况下执行合并操作,因为否则由于数据块中空闲空间的不断合并,性能会下降。
索引空间的重用 数据库可以在索引块内重用空间。例如,如果您插入一个值到某一列并将其删除,并且如果这一列上存在索引,那么当一行需要时,数据库可以重用索引槽位。数据库可以重用索引块本身。与表块不同,索引块仅在为空时才变为空闲。数据库将空块放置在索引结构的空闲列表上,并使其有资格被重用。然而,Oracle 数据库不会自动压缩索引:需要执行 ALTER INDEX REBUILD 或 COALESCE 语句。图12-12表示在索引合并之前 employees.department_id 列的索引。前三个叶块只有部分填充,如图中的灰色填充线所示。
图12-13显示了图12-12中的索引在合并后的索引。前两个叶块现在已满,如图中的灰色填充线所示,第三个叶块已被释放。
12.2.4.3. 链式和迁移行
Oracle 数据库必须管理那些太大而无法放入单个数据块中的行。可能出现以下情况:
■ 当首次插入时,一行太大了,无法放入一个数据块中。
在行链式存储中,Oracle 数据库将行的数据存储在为段保留的一个或多个数据块的链中。行链式存储最常发生在大型行上。例子包括包含数据类型为LONG或LONG RAW的列、2 KB块中的VARCHAR2(4000)列,或者具有大量列的行。在这些情况下,行链式存储是不可避免的。
■ 一行最初适合放入一个数据块中,但更新后整体行长度增加,但不存在足够的空闲空间来容纳更新后的行。在行迁移中,Oracle 数据库将整个行移动到一个新的数据块中,假设该行可以放入一个新的块中。迁移行的原始行片段包含指向包含迁移行的新块的指针或“转发地址”。迁移行的rowid不会改变。
■ 一行有超过255个列。Oracle 数据库只能在一个行片段中存储255列。因此,如果您向具有1000列的表中插入一行,数据库将创建4个行片段,通常分散在多个块中。
图12-14显示了在数据块中插入大型行的情况。该行对于左侧的块来说太大了,因此数据库通过将第一行片段放置在左侧块中,将第二行片段放置在右侧块中,从而将该行进行了链式存储。
图12-15中,左侧块包含一行,该行经过更新后变得太大而无法放入该块中。数据库将整个行移动到右侧块,并在左侧块中留下一个指向迁移行的指针。
当一行被链式存储或迁移时,检索数据所需的I/O会增加。这种情况之所以发生,是因为Oracle 数据库必须扫描多个块来检索该行的信息。例如,如果数据库执行一次I/O来读取索引,执行一次I/O来读取未迁移的表行,那么就需要额外的I/O来获取迁移行的数据。
段顾问(Segment Advisor)是Oracle 数据库的一个组件,它可以手动和自动运行,用于识别有空间可以回收的段。该顾问可以提供关于有大量空闲空间或链式行过多的对象的建议。
12.3. 区概述
一个区(extent)是由一组连续的数据块组成的数据库存储空间的逻辑分配单位。区中的数据块在逻辑上是连续的,但可能会因为RAID条带化和文件系统实现而在物理上分散在磁盘上。
12.3.1. 区空间分配
默认情况下,当创建段时,数据库会为数据段分配一个初始区。一个区总是包含在一个数据文件中。尽管还没有数据被添加到段中,但初始区中的数据块是专门为这个段保留的。每个段的第一个数据块包含该段中区的目录。图12-16显示了一个之前不包含任何数据的数据文件中的段的初始区。
如果初始区变满,并且需要更多的空间,那么数据库会自动为这个段分配一个增量区。增量区是为段创建的后续区。
分配算法取决于表空间是本地管理的还是字典管理的。在本地管理的情况下,数据库会在数据文件的位图中搜索相邻的空闲块。如果数据文件空间不足,数据库则会在另一个数据文件中查找。段的区始终位于同一个表空间中,但可能位于不同的数据文件中。
图12-17显示,数据库可以为表空间中的任何数据文件中的段分配区。例如,段可以在users01.dbf中分配初始区,在users02.dbf中分配第一个增量区,并在users01.dbf中分配下一个区。
新分配区的块,尽管它们是空闲的,但可能并不为空旧数据。在自动段空间管理(ASSM)中,Oracle 数据库在开始使用新分配的区时会格式化该区的块,但仅在需要时这样做(参见第12-27页的“段空间和高水位标记”)。
注意:本节适用于串行操作,在串行操作中,一个服务器进程解析并运行语句。在涉及多个服务器进程的并行SQL语句中,区的分配方式不同。
12.3.2. 区空间的释放
通常情况下,用户段的区不会返回到表空间,除非你使用 DROP 命令删除对象。在 Oracle Database 11g Release 2 (11.2.0.2) 中,你还可以使用 DBMS_SPACE_ADMIN 包来删除段。例如,如果你删除了表中的所有行,那么数据库不会将数据块回收供表空间中的其他对象使用。
注意:在 undo 段中,如果指定了最优大小,或者数据库处于自动 undo 管理模式(参见第12-33页的“Undo 表空间”),Oracle 数据库会定期释放一个或多个区。
在某些情况下,你可以手动释放空间。Oracle 段顾问可以帮助确定对象是否有足够的碎片空间可以回收。以下技术可以释放区:
■ 你可以使用在线段收缩来回收段中的碎片空间。段收缩是一个在线的、原地操作。通常,数据压缩可以提高缓存利用率,并减少全表扫描时需要读取的块数。
■ 你可以将非分区表或表分区的数据移动到一个新的段中,并且可以选择移动到你拥有配额的不同表空间中。
■ 你可以重建或合并索引(参见第12-14页的“索引空间的重用”)。
■ 你可以截断表或表簇,这将删除所有行。默认情况下,Oracle 数据库会释放被移除行使用的所有空间,除了由MINEXTENTS存储参数指定的空间。在 Oracle Database 11g Release 2 (11.2.0.2) 中,你还可以使用带有 DROP ALL STORAGE 选项的 TRUNCATE 来删除整个段。
■ 你可以释放未使用的空间,这会释放数据库段高端的未使用空间,并使空间在表空间中的其他段可用(参见第12-27页的“段空间和高水位标记”)。
当区被释放时,Oracle 数据库会修改本地管理表空间数据文件中的位图,以反映恢复的区作为可用空间。释放区中的任何数据块都变得无法访问。
12.3.3. 区空间的存储参数
每个段都由以区为单位的存储参数定义。这些参数控制Oracle数据库如何为段分配空闲空间。存储设置按照以下优先级顺序确定,列表中位置越高的设置会覆盖位置越低的设置:
- 段存储子句
- 表空间存储子句
- Oracle数据库默认值
本地管理的表空间可以有统一的区大小或由系统自动确定的可变区大小:
■ 对于统一区,你可以指定区大小或使用默认大小1 MB。表空间中的所有区都是这个大小。本地管理的临时表空间只能使用这种类型的分配。
■ 对于自动分配的区,Oracle数据库会确定额外区的最优大小。
对于本地管理的表空间,有些存储参数不能在表空间级别指定。然而,你可以在段级别指定这些参数。在这种情况下,数据库使用所有参数一起计算段的初始大小。内部算法确定每个区的后续大小。
12.4. 段概述
段是一组区,包含了表空间内一个逻辑存储结构的所有数据。例如,Oracle 数据库分配一个或多个区来形成表的数据段。数据库还分配一个或多个区来形成表的索引段。
正如在“逻辑空间管理”中解释的,Oracle 数据库自动或手动管理段空间。本节假设使用的是自动段空间管理(ASSM)。
12.4.1. 用户段
数据库中的单个数据段存储了一个用户对象的数据。有不同类型的段。用户段的例子包括:
■ 表、表分区或表簇
■ LOB或LOB分区
■ 索引或索引分区
每个非分区对象和对象分区都存储在自己的段中。例如,如果一个索引有五个分区,那么五个段包含索引数据。
用户段创建:默认情况下,数据库使用延迟段创建,在创建表和索引时只更新数据库元数据。从Oracle Database 11g Release 2 (11.2.0.2)开始,数据库在创建分区时也延迟段创建。当用户向表或分区插入第一行时,数据库为表或分区、其LOB列和索引创建段。
延迟段创建使您能够避免不必要的使用数据库资源。例如,应用程序的安装可以创建数千个对象,消耗大量的磁盘空间。这些对象中的许多可能永远不会被使用。
您可以使用DBMS_SPACE_ADMIN包来管理空对象的段。从Oracle Database 11g Release 2 (11.2.0.2)开始,您可以使用这个PL/SQL包来执行以下操作:
■ 为尚未创建段的空表或分区手动实现段
■ 从当前有分配空段的空表或分区中移除段
为了最好地说明对象创建和段创建之间的关系,假设禁用了延迟段创建。您如下创建一个表:
CREATE TABLE test_table (my_column NUMBER);
如图12-18所示,数据库为该表创建了一个段。
当您创建一个带有主键或唯一键的表时,Oracle 数据库会自动为这个键创建一个索引。再次假设禁用了延迟段创建。您如下创建一个表:
CREATE TABLE lob_table (my_column NUMBER PRIMARY KEY, clob_column CLOB);
图12-19显示了lob_table的数据存储在一个段中,而隐式创建的索引存储在另一个不同的段中。同样,CLOB数据存储在自己的段中,其关联的CLOB索引也是如此(参见第19-12页的“内部LOBs”)。因此,CREATE TABLE语句导致了四个不同段的创建。
注意:表的段和该表的索引不必占用同一个表空间。
在创建段时,数据库会分配一个或多个区。对象的存储参数决定了如何为每个段分配区(参见第12-20页的“区的存储参数”)。这些参数影响与对象相关联的数据段的数据处理和存储效率。
12.4.2. 临时段
在处理查询时,Oracle 数据库通常需要临时工作空间来执行SQL语句执行的中间阶段。可能需要临时段的典型操作包括排序、哈希和合并位图。在创建索引时,Oracle 数据库还将索引段放入临时段,然后在索引完成时将它们转换为永久段。
如果操作可以在内存中执行,Oracle 数据库不会创建临时段。然而,如果无法使用内存,则数据库会自动在磁盘上分配一个临时段。
12.4.2.1. 临时段为查询分配临时段
Oracle 数据库在用户会话期间根据需要为查询分配临时段,并在查询完成时删除它们。临时段的更改不会记录在在线重做日志中,除非是针对临时段进行的空间管理操作(参见第11-12页的“在线重做日志概述”)。数据库在分配给用户的临时表空间中创建临时段。表空间的默认存储特性决定了临时段中区的特性。由于临时段的分配和回收经常发生,最佳实践是至少创建一个特殊的表空间用于临时段。数据库会在磁盘间分配I/O,并避免使用临时段来碎片化SYSTEM和其他表空间。
注意:当SYSTEM表空间为本地管理时,你必须在数据库创建时定义一个默认的临时表空间。本地管理的SYSTEM表空间不能用作默认的临时存储。
12.4.2.2. 为临时表和索引分配临时段
Oracle 数据库也可以为临时表及其索引分配临时段。临时表存储的数据只存在于事务或会话期间。每个会话只能访问为该会话分配的区,而不能访问为其他会话分配的区。
当首次向临时表中插入数据时,Oracle 数据库会为该临时表分配段。插入可以是显式的,也可以是因为 CREATE TABLE AS SELECT。首次向临时表插入数据会为表及其索引分配段,创建索引的根页面,并分配任何LOB段。
临时表的段是在当前用户的临时表空间中分配的。假设分配给user1的临时表空间是temp1,分配给user2的临时表空间是temp2。在这种情况下,user1在temp1段中存储临时数据,而user2在temp2段中存储临时数据。
12.4.3. 回滚段
Oracle 数据库维护事务操作的记录,统称为 undo 数据。Oracle 数据库使用 undo 来执行以下操作:
■ 回滚活动事务
■ 恢复终止的事务
■ 提供读取一致性
■ 执行一些逻辑闪回操作
Oracle 数据库将 undo 数据存储在数据库内部,而不是外部日志中。Undo 数据存储在块中,这些块像数据块一样被更新,这些块的更改会产生重做(redo)。通过这种方式,Oracle 数据库可以高效地访问 undo 数据,而不需要读取外部日志。
Undo 数据存储在 undo 表空间中。Oracle 数据库提供了一个全自动机制,称为自动 undo 管理模式,用于管理 undo 段和 undo 表空间中的空间。
12.4.3.1. Undo段和事务
当事务开始时,数据库会将事务绑定(分配)到当前 undo 表空间中的一个 undo 段,以及事务表。在极少数情况下,如果数据库实例没有指定的 undo 表空间,那么事务会绑定到系统 undo 段。
多个活动事务可以并发地写入同一个 undo 段或不同的段。例如,事务T1和T2都可以写入undo段U1,或者T1写入U1而T2写入undo段 U2。
从概念上讲,undo段中的区形成一个环。事务先写入一个undo区,然后写入环中的下一个区,依此类推,以循环方式进行。图12-20显示了两个事务 T1 和 T2,它们从 undo 段的第三个区(E3)开始写入,并继续写入第四个区(E4)。
在任何给定时间,一个事务只会顺序写入 undo 段中的一个区,这个区被称为事务的当前区。多个活动事务可以同时写入同一个当前区或不同的当前区。图12-20显示了事务T1和T2同时写入区E3。
在一个 undo 区内,一个数据块只包含一个事务的数据。
随着当前 undo 区逐渐填满,第一个需要空间的事务会检查环中下一个已分配区的可用性。如果下一个区不包含活动事务的数据,那么这个区就成为当前区。现在所有需要空间的事务都可以写入新的当前区。在图12-21中,当E4满时,T1和T2继续写入E1,覆盖E1中的非活动 undo 数据。
如果下一个区确实包含活动事务的数据,那么数据库必须分配一个新的区。图12-22显示了一种情况,其中T1和T2正在写入E4。当E4填满时,事务不能继续写入E1,因为E1包含活动的 undo 条目。因此,数据库为这个 undo 段分配了一个新的区(E5)。事务继续写入E5。
12.4.3.2. 事务回滚
当发出 ROLLBACK 语句时,数据库使用 undo 记录来回滚未提交事务对数据库所做的更改。在恢复过程中,数据库会回滚在线重做日志对数据文件应用的任何未提交的更改。Undo 记录通过维护数据的旧版本来提供读取一致性,以便在另一个用户更改数据的同时访问数据的用户可以读取到更改前的数据。
12.4.4. 段空间和高水位
为了管理空间,Oracle 数据库跟踪段中块的状态。高水位标记(HWM)是段中数据块未格式化且从未使用过的点。
手动段空间管理(MSSM)使用空闲列表来管理段空间。在创建表时,段中没有块被格式化。当会话首次向表中插入行时,数据库会在空闲列表中搜索可用块。如果数据库没有找到可用块,则它会预格式化一组块,将它们放置在空闲列表上,并开始将数据插入这些块中。在MSSM中,全表扫描会读取高水位标记下的所有块。
自动段空间管理(ASSM)不使用空闲列表,因此必须以不同的方式管理空间。当会话首次向表中插入数据时,数据库会格式化一个单独的位图块,而不是像MSSM那样预格式化一组块。位图跟踪段中块的状态,取代了空闲列表。数据库使用位图来查找空闲块,然后在用数据填充之前格式化每个块。ASSM将插入操作分散到多个块中,以避免并发问题。
在ASSM段中,每个数据块都处于以下状态之一:
■ 高于高水位标记(HWM)这些块未格式化,且从未被使用过。
■ 低于高水位标记(HWM)这些块处于以下状态之一:
– 分配了,但目前未格式化且未使用
– 已格式化并包含数据
– 已格式化且为空,因为数据已被删除
图12-23将ASSM段描绘成一系列水平的块。在创建表时,HWM位于段的最左侧起始处。由于尚未插入任何数据,段中的所有块都是未格式化且从未使用过的。
假设一个事务向段中插入行。数据库必须分配一组块来存储这些行。分配的块位于高水位标记(HWM)之下。数据库在该组中格式化一个位图块来保存元数据,但不会预格式化组中的其余块。在图12-24中,低于HWM的块被分配了,而高于HWM的块既没有被分配也没有被格式化。随着插入操作的发生,数据库可以写入任何有可用空间的块。低高水位标记(低HWM)标志着所有块都已知为格式化的点,因为它们要么包含数据,要么曾经包含数据。
在图12-25中,数据库在高水位标记(HWM)和低水位标记(low HWM)之间的某个块中选择一个块并写入数据。数据库本可以同样容易地选择HWM和低HWM之间的任何其他块,或者选择低HWM下方有可用空间的任何块。在图12-25中,新填充块两侧的块都是未格式化的。
低 HWM 在全表扫描中很重要。因为只有在使用时才格式化低于 HWM 的块,所以有些块可能是未格式化的,如图12-25所示。因此,数据库读取位图块以获取低 HWM 的位置。数据库读取所有低 HWM 以下的块,因为它们已知是格式化的,然后仔细读取低 HWM 和 HWM 之间的格式化块。
假设一个新事务向表中插入行,但位图显示在 HWM 下方没有足够的空闲空间。在图12-26中,数据库将 HWM 向右推进,分配了一组新的未格式化块。
当位于 HWM 和低 HWM 之间的块已满时,HWM 会向右移动,低 HWM 会移动到旧 HWM 的位置。随着数据库不断插入数据,HWM 会继续向右移动,而低 HWM 总是跟在它后面。除非你手动重建、截断或收缩对象,否则 HWM 永远不会后退。
12.5. 表空间概述
表空间是段的逻辑存储容器。段是消耗存储空间的数据库对象,如表和索引。在物理层面,表空间将数据存储在一个或多个数据文件或临时文件中。数据库必须有 SYSTEM 和 SYSAUX 表空间。图12-27显示了一个典型数据库中的表空间。以下部分描述了表空间类型。
12.5.1. 永久表空间
永久表空间用于组织持久化的模式对象。表空间中的对象段在物理上存储在数据文件中。每个数据库用户都被分配了一个默认的永久表空间。一个非常小的数据库可能只需要默认的SYSTEM和SYSAUX表空间。然而,Oracle建议至少创建一个表空间来存储用户和应用程序数据。你可以使用表空间来实现以下目标:
■ 控制数据库数据的磁盘空间分配
■ 为数据库用户分配配额(空间允许量或限制)
■ 在不影响整个数据库可用性的情况下,将个别表空间上线或下线
■ 对个别表空间执行备份和恢复
■ 使用Oracle Data Pump实用程序导入或导出应用程序数据(参见第18-7页的“Oracle Data Pump导出和导入”)
■ 创建可传输表空间,你可以将其从一个数据库复制或移动到另一个数据库,甚至跨平台
通过传输表空间移动数据比导出/导入或卸载/加载相同数据的速度快几个数量级,因为传输表空间只涉及复制数据文件和整合表空间元数据。当你传输表空间时,你也可以移动索引数据。
12.5.1.1. 系统表空间
SYSTEM 表空间是在创建数据库时包含的必要的行政表空间。Oracle 数据库使用 SYSTEM 来管理数据库。SYSTEM 表空间包括以下信息,所有这些都由 SYS 用户拥有:
■ 数据字典
■ 包含数据库管理信息的表和视图
■ 编译后存储的对象,如触发器、过程和包
SYSTEM 表空间像其他表空间一样进行管理,但需要更高级别的权限,并在某些方面受到限制。例如,你不能重命名或删除 SYSTEM 表空间。
默认情况下,Oracle 数据库将所有新创建的用户表空间设置为本地管理。在具有本地管理 SYSTEM 表空间的数据库中,你不能创建字典管理的表空间(已被弃用)。然而,如果你手动执行 CREATE DATABASE 语句并接受默认值,那么 SYSTEM 表空间就是字典管理的。你可以将现有的字典管理 SYSTEM 表空间迁移到本地管理模式。
注意:Oracle 强烈建议使用数据库配置助手(DBCA)创建新数据库,以便所有表空间,包括 SYSTEM,默认情况下都是本地管理的。
12.5.1.2. SYSAUX表空间
SYSAUX 表空间是 SYSTEM 表空间的辅助表空间。SYSAUX 表空间提供了一个集中的位置来存储不位于 SYSTEM 表空间中的数据库元数据。它减少了在种子数据库和用户定义数据库中默认创建的表空间数量。
包括 Oracle Enterprise Manager 和 Oracle Streams 在内的多个数据库组件使用 SYSAUX 表空间作为它们的默认存储位置。因此,在数据库创建或升级过程中,SYSAUX 表空间会自动创建。
在正常的数据库操作中,数据库不允许删除或重命名SYSAUX 表空间。如果 SYSAUX 表空间变得不可用,那么核心数据库功能仍然可以运行。使用 SYSAUX 表空间的数据库功能可能会失败,或者功能受限。
Undo表空间 Undo表空间是一个本地管理的表空间,专门用于系统管理的 undo 数据(见第12-24页的“Undo 段”)。像其他永久表空间一样,undo 表空间包含数据文件。这些文件中的 undo 块被分组在区中。
自动Undo管理模式 Undo表空间要求数据库处于默认的自动undo管理模式。这种模式消除了手动管理 undo 段的复杂性。数据库自动调整自身,以提供最佳的 undo 数据保留,以满足可能需要这些数据的长时间运行的查询。在新的 Oracle 数据库安装中,会自动创建 undo 表空间。早期版本的 Oracle 数据库可能不包括 undo 表空间,而是使用传统的回滚段,称为手动 undo 管理模式。在升级到 Oracle Database 11g 时,你可以启用自动 undo 管理模式并创建一个 undo 表空间。Oracle 数据库包含一个Undo顾问,提供建议并帮助自动化你的 undo 环境。数据库可以包含多个 undo 表空间,但一次只能使用一个。当实例尝试打开数据库时,Oracle 数据库自动选择第一个可用的undo表空间。如果没有undo表空间可用,那么实例会在没有undo表空间的情况下启动,并将undo数据存储在SYSTEM表空间中。不推荐在SYSTEM中存储undo数据。
自动Undo保留期 Undo保留期是Oracle数据库在覆盖旧的undo数据之前尝试保留旧undo数据的最短时间。Undo保留期很重要,因为长时间运行的查询可能需要旧的块映像来提供读取一致性。此外,某些 Oracle 闪回功能可能依赖于 undo 的可用性。
通常情况下,尽可能长时间地保留旧的undo数据是可取的。事务提交后,undo数据不再需要用于回滚或事务恢复。如果undo表空间有空间进行新事务,数据库可以保留旧的undo数据。当可用空间较低时,数据库开始覆盖已提交事务的旧undo数据。
Oracle数据库自动为当前undo表空间提供最佳的undo保留。数据库收集使用情况统计信息,并根据这些统计信息和undo表空间大小调整保留期。如果undo表空间配置了AUTOEXTEND选项,并且如果没有指定最大大小,那么undo保留调整则不同。在这种情况下,如果空间允许,数据库将undo保留期调整为比运行时间最长的查询稍长。
12.5.2. 临时表空间
临时表空间包含仅在会话期间持续存在的临时数据。临时表空间中不能存放永久模式对象。数据库将临时表空间数据存储在临时文件中。临时表空间可以提高多个无法适应内存的排序操作的并发性。这些表空间还提高了排序期间空间管理操作的效率。当 SYSTEM 表空间为本地管理时,在数据库创建过程中,默认会包含一个默认的临时表空间。本地管理的 SYSTEM 表空间不能作为默认的临时存储。
注意:您不能将默认的临时表空间变为永久表空间。
当您使用 CREATE DATABASE 语句的 DEFAULT TEMPORARY TABLESPACE 扩展创建数据库时,可以指定一个用户命名的默认临时表空间。如果 SYSTEM 是字典管理的,并且在数据库创建时没有定义默认临时表空间,那么 SYSTEM 就是默认的临时存储。然而,数据库会在警报日志中写入一条警告,建议设置一个默认的临时表空间。
12.5.3. 表空间模式
表空间模式决定了表空间的可访问性。
12.5.3.1. 读写和只读表空间
每个表空间都有一个写入模式,指定是否可以向其写入数据。它们是互斥的,如下所示:
■ 读写模式
用户可以读取和写入表空间。所有表空间最初都是以读写模式创建的。SYSTEM 和 SYSAUX 表空间以及临时表空间永久是读写模式,这意味着它们不能被设置为只读。
■ 只读模式
防止向表空间的数据文件执行写操作。只读表空间可以位于如 DVD 或 WORM 驱动器这样的只读媒体上。
只读表空间消除了对数据库中大型、静态部分执行备份和恢复的需求。只读表空间不会改变,因此不需要重复备份。如果在媒体故障后恢复数据库,那么不需要恢复只读表空间。
12.5.3.2. 在线和离线表空间
表空间可以是在线的(可访问的)或离线的(不可访问的),无论数据库是否打开。表空间通常处于在线状态,以便用户可以访问其数据。SYSTEM 表空间和临时表空间不能离线。表空间可以自动或手动离线。例如,您可以将表空间离线以进行维护或备份和恢复。当遇到某些错误时,数据库会自动将表空间离线,比如数据库写入(DBW)进程多次尝试写入数据文件失败时。尝试访问离线表空间中的表的用户会收到错误。当表空间离线时,数据库会执行以下操作:
■ 数据库不允许随后的 DML 语句引用离线表空间中的对象。离线表空间不能被 Oracle 数据库以外的任何实用程序读取或编辑。
■ 已完成语句的活跃事务在事务级别不受影响。
■ 数据库将与这些已完成语句对应的 undo 数据保存在 SYSTEM 表空间中的延迟 undo 段中。当表空间重新上线时,数据库会根据需要将 undo 数据应用到表空间。
12.5.4. 表空间文件大小
表空间可以是大文件表空间或小文件表空间。在执行不显式引用数据文件或临时文件的 SQL 语句方面,这两种表空间无法区分。它们的区别如下:
■ 小文件表空间可以包含多个数据文件或临时文件,但这些文件不能像大文件表空间中那样大。这是默认的表空间类型。
■ 大文件表空间包含一个非常大的数据文件或临时文件。这种类型的表空间可以执行以下操作:
– 增加数据库的存储容量
数据库中数据文件的最大数量是有限的(通常限制在64 KB文件),因此增加每个数据文件的大小可以增加整体存储。
– 减少管理多个数据文件和临时文件的负担
大文件表空间通过消除添加新文件和处理多个文件的需要,简化了 Oracle 管理文件和自动存储管理(Oracle ASM)的文件管理。
– 对表空间而不是单个文件执行操作
大文件表空间使表空间成为磁盘空间管理、备份和恢复等的主要单位。
大文件表空间仅支持使用 ASSM 的本地管理表空间。然而,即使段是手动管理的,本地管理的 undo 和临时表空间也可以是大文件表空间。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!