千家信息网最后更新 2024年11月25日Oracle 数据块体系基础知识概述
Oracle 数据块体系基础知识概述
数据块概述
Oracle对数据库数据文件(datafile)中的存储空间进行管理的单位是数据块(data block)。数据块是数据库中最小的(逻辑)数据单位。与数据块对应的,所有数据在操作系统级的最小物理存储单位是字节(byte)。每种操作系统都有一个被称为块容量(block size)的参数。Oracle每次获取数据时,总是访问整个数(Oracle)数据块,而不是按照操作系统块的容量访问数据。
数据库中标准的数据块(data block)容量是由初始化参数 DB_BLOCK_SIZE 指定的。除此之外,用户还可以指定五个非标准的数据块容量(nonstandard block size)。数据块容量应该设为操作系统块容量的整数倍(同时小于数据块容量的最大限制),以便减少不必要的I/O操作。Oracle数据块是Oracle可以使用和分配的最小存储单位。
2.2.1 数据块结构
在Oracle中,不论数据块中存储的是表(table)、索引(index)或簇表(clustered data),其内部结构都是类似的。
图2-1 数据块结构
本图显示了数据块的各个组成部分,包括:数据块头(包括标准内容和可变内容)(common and variable header),表目录区(table directory),行目录区(row directory),可用空间区(free space),行数据区(row data)。以下各节将分别讲解各个组成部分。图中两个箭头表示一个数据块中的可用空间区的容量是可变的。
2.2.1.1 数据块头(包括标准内容和可变内容)
数据块头(header)中包含了此数据块的概要信息,包括块地址(block disk address)及此数据块所属的段(segment)的类型(例如,表或索引)。
-
Block header
This part contains general information about the block, including disk address and segment type. For blocks that are transaction-managed, the block header contains active and historical transaction information.
A transaction entry is required for every transaction that updates the block. Oracle Database initially reserves space in the block header for transaction entries. In data blocks allocated to segments that support transactional changes, free space can also hold transaction entries when the header space is depleted. The space required for transaction entries is operating system dependent. However, transaction entries in most operating systems require approximately 23 bytes.
数据块头
这部分包含了关于数据块的块地址(在磁盘上的地址)和段类型一般信息。对于那些事务型数据块,它们的块头还包含了当前和历史事务信息。
一个事务记录被每一个更新数据块的事务所需求。oracle数据块初始时在数据块头中为事务记录保留了空间。在分配给支持事务变化的段的数据块时,当块头空间耗尽时,空闲空间也能保留事务记录。事务记录所需要的空间是操作系统依赖的。然而,在大多数操作系统中事务记录大约需要23bytes空间。
2.2.1.2 表目录区
如果一个数据表在此数据块中储存了数据行,那么数据表的信息将被记录在数据块的表目录区(table directory)中。
-
Table directory
For a heap-organized table, this directory contains metadata about tables whose rows are stored in this block. Multiple tables can store rows in the same block.
表目录
对于堆表来说,这个目录包含了存储在这个块中的表的元数据,多个表能够在相同的数据块中存储行。
2.2.1.3 行目录区
此区域包含数据块中存储的数据行的信息(每个数据行片断(row piece) 在行数据区(row data area)中的地址)。[一个数据块中可能保存一个完整的数据行,也可能只保存数据行的一部分 ,所以文中使用row piece
当一个数据块(data block)的行目录区(row directory)空间被使用后,即使数据行被删除(delete),行目录区空间也不会被回收。举例来说,当一个曾经包含50条记录的数据块被清空后,其块头(header)的行目录区仍然占用100字节(byte)的空间。只有在数据块中插入(insert)新数据时,行目录区空间才会被 重新利用。
-
Row directory
For a heap-organized table, this directory describes the location of rows in the data portion of the block.
After space has been allocated in the row directory, the database does not reclaim this space after row deletion. Thus, a block that is currently empty but formerly had up to 50 rows continues to have 100 bytes allocated for the row directory. The database reuses this space only when new rows are inserted in the block.
行目录
对于一个堆表来说,这个目录描述了行在数据块中 的位置。
在行目录中,空间被分配之后,数据库不会在行删除之后重新声明这个空间。另外,一个数据块当前是空的,但是之前已经到达了50行记录,会持续保持已分配的100bytes空间。数据库只有当新的行插入时才会使用这个空间。(HWM)
2.2.1.4 管理开销
数据块头(data block header),表目录区(table directory),行目录区(row directory)被统称为管理开销(overhead)。其中 有些开销的容量是固定的;而有些开销的总容量是可变的。数据块中固定及可变管理开销的容量平均在84到107字节(byte)之间。
Oracle Database uses the block overhead to manage the block itself. The block overhead is not available to store user data.
oracle数据库使用块管理开销来管理本身。管理开销不能用来存储用户数据。
Some parts of the block overhead are fixed in size, but the total size is variable. On average, the block overhead totals 84 to 107 bytes.
部分数据块开销是固定的,但是总大小是可变的。一般来说,数据块开销一般为84-107bytes。
2.2.1.5 行
数据块(data block)中行数据区(row data)包含了表或索引的实际数据。一个数据行可以跨多个数据块。这就出现了"行链接(Row Chaining)及行迁移(Row Migrating)
Row Format
The row data part of the block contains the actual data, such as table rows or index key entries. Just as every data block has an internal format, every row has a row format that enables the database to track the data in the row.
Oracle Database stores rows as variable-length records. A row is contained in one or more row pieces. Each row piece has a row header and column data.
块的行数据部分包含了真实的数据,例如表行或者索引记录。正如每个数据块有一个内部格式一样,每个行也有行格式,使得数据库能够追踪到行里的数据(row是由一个或多个piece组成的)。
Figure 12-7 shows the format of a row.
Row Header
Oracle Database uses the row header to manage the row piece stored in the block. The row header contains information such as the following:
-
Columns in the row piece
-
Pieces of the row located in other data blocks
If an entire row can be inserted into a single data block, then Oracle Database stores the row as one row piece. However, if all of the row data cannot be inserted into a single block or an update causes an existing row to outgrow its block, then the database stores the row in multiple row pieces (see"Chained and Migrated Rows"). A data block usually contains only one row piece per row.
-
Cluster keys for table clusters (see "Overview of Table Clusters")
A row fully contained in one block has at least 3 bytes of row header.
行头包含的信息:
行片断中的列、位于其他数据块的行片断的位置、聚簇表的关键字。
一行在数据块中被完全包含至少需要3btyes的行头空间。
Column Data
After the row header, the column data section stores the actual data in the row. The row piece usually stores columns in the order listed in the CREATE TABLE
statement, but this order is not guaranteed. For example, columns of type LONG
are created last.
As shown in Figure 12-7, for each column in a row piece, Oracle Database stores the column length and data separately. The space required depends on the data type. If the data type of a column is variable length, then the space required to hold a value can grow and shrink with updates to the data.
Each row has a slot in the row directory of the data block header. The slot points to the beginning of the row.
在行头后面,列数据部分存储了行的真实数据。行片通常存储在CREATE TABLE命令中列出的列,但是命令不能够保证这一点。例如,LONG类型的列创建时。
如上图所示,对行片中的每一个列,oracle数据库都单独地存储列的长度和数据。所需要的空间取决于数据类型。如果列的数据类型是可变长度,那么空间需要保持为一个可被update的增长和压缩的值。
Rowid Format
Oracle Database uses a rowid to uniquely identify a row. Internally, the rowid is a structure that holds information that the database needs to access a row. A rowid is not physically stored in the database, but is inferred from the file and block on which the data is stored.
oracle数据库用rowid来唯一指定一行。rowid是一种保留数据库需要获取一行的信息的内在结构。rowid并不会物理存储在数据库中,但是是由存储数据的数据块或者文件推断而来(这句话的意思是rowid不是数据库数据,但是它仍然占用了磁盘空间)。
An extended rowid includes a data object number. This rowid type uses a base64 encoding of the physical address for each row. The encoding characters are A-Z
, a-z
, 0-9
, +
, and /
.
可扩展的rowid包括数据对象号码。这种rowid类型对每个数据行的物理地址使用了base64 编码。这种编码字符包括:A-Z,a-z,0-9,+和 /。
Example queries the ROWID
pseudocolumn to show the extended rowid of the row in the employees
table for employee 100.
ROWID Pseudocolumn
SQL> SELECT ROWID FROM employees WHERE employee_id = 100; ROWID ------------------ AAAPecAAFAAAABSAAA
Figure 12-8 illustrates the format of an extended rowid.
An extended rowid is displayed in a four-piece format, OOOOOOFFFBBBBBBRRR
, with the format divided into the following components:
-
OOOOOO
The data object number identifies the segment (data object AAAPec
in Example 12-1). A data object number is assigned to every database segment. Schema objects in the same segment, such as a table cluster, have the same data object number.
-
FFF
The tablespace-relative data file number identifies the data file that contains the row (file AAF
in Example 12-1).
-
BBBBBB
The data block number identifies the block that contains the row (block AAAABS
in Example 12-1). Block numbers are relative to their data file, not their tablespace. Thus, two rows with identical block numbers could reside in different data files of the same tablespace.
-
RRR
The row number identifies the row in the block (row AAA
in Example 12-1).
- 数据对象编号指定了段。数据对象编号被分配给每个段。在相同段中的方案对象,例如聚簇表,拥有相同的数据对象编号。
- 表空间相关的数据文件编号指定了包含行的数据文件。
- 行编号指定了数据块中的行。
After a rowid is assigned to a row piece, the rowid can change in special circumstances. For example, if row movement is enabled, then the rowid can change because of partition key updates, Flashback Table operations, shrink table operations, and so on. If row movement is disabled, then a rowid can change if the row is exported and imported using Oracle Database utilities.
在一个rowid分配给一个行片后,rowid能够在特殊的环境下改变。例如,如果行移动开启了,那么rowid能够因为分区键更新、闪回表操作、压缩表等改变。如果行迁移关闭了,那么如果行使用oracle工具进行导入导出时,rowid会改变。
2.2.1.6 可用空间区
在插入新数据行,或在更新数据行需要更多空间时(例如,原来某行最后一个字段为空(trailing null),现在要更新为非空值),将 使用可用空间区(free space)中的空间。
如果一个数据块(data block)属于表或簇表的数据段(data segment),或属于索引的索引段(index segment),那么在其可用空间区中还可能会存储事务条目(transaction entry)。如果一个数据块中的数据行(row)正在由 INSERT,UPDATE,DELETE,及 SELECT...FOR UPDATE 语句访问,此数据块中就需要保存事务条目。事务条目所需的存储空间依据操作系统而定。在常见的操作系统中事务条目大约需要有两种SQL语句可以增加数据块中的可用空间:分别是 DELETE 语句,和将现有数据值更新为占用容量更小值的 UPDATE 语句。在以下两种条件下,上述两中操作释放的空间可以被后续的 INSERT 语句使用:
如果 INSERT 语句与上述两种操作在同一事务(transaction)中,且位于释放空间的语句之后,那么 INSERT 语句可以使用被释放的空间。
如果 INSERT 语句与释放空间的语句在不同的事务中(比如两者是由不同的用户提交的),那么只有在释放空间的语句提交后,且插入数据必需使用此数据块时,INSERT 语句才会使用被释放的空间。
数据块(data block)中被释放出的空间未必与可用空间区(free space)相连续。Oracle在满足以下条件时才会将释放的空间合并到可用空间区:
(1)INSERT 或 UPDATE 语句选中了一个有足够可用空间容纳新数据的数据块;
(2)但是此块中的可用空间不连续,数据无法被写入到数据块中连续的空间里。Oracle只在 满足上述条件时才对数据块中的可用空间进行合并,这样做是为了避免过于频繁的空间合并工作影响数据库性能。
2.2.2.2 行链接(Row Chaining)及行迁移(Row Migrating)
有两种情况会导致表中某行数据过大,一个数据块(data block)无法容纳。一种情况是行链接( Row Chaining ),
另一种情况是行迁移 (Row Migrating)。当数据行发生链接(chain)或迁移(migrate)时,对其访问将会造成 I/O 性能降低,因为Oracle为获取这些数据行的数据时,必须访问更多的数据块(data block)。
行链接( Row Chaining ):如果我们往数据库中插入( INSERT )一行数据,这行数据很大,以至于一个数据块存不下一整行, Oracle 就会把一行数据分作几段存在几个数据块中,这个过程叫行链接( Row Chaining )。在这种情况下Oracle将这行数据存储在段内的一个数据块链(chain)中。在插入数据量大的行时常会发生行链接(row chaining),例如一个包含数据类型为 LONG 或 LONG RAW 列的数据行。此时行链接不可避免。 行链接又称为行跨页(Oracle允许行跨页,但DB2是不允许的)。
行迁移 (Row Migrating) :原本存储在一个数据块(data block)内的数据行,因为更新操作导致长度增长,而所在数据块的可用空间也不能容纳增长后的数据行。在这种情况下,Oracle将此行数据迁移(migrate)到新的数据块中。Oracle在被迁移数据行原来所在位置保存一个指向新数据块的指针。被迁移数据行的 rowid 保持不变。 PCTFREE 参数用于指定块中必须保留的最小空闲空间百分例。之所以要预留这样的空间,是因为 UPDATE 时,需要这些空间。如果 UPDATE 时,没有空余空间, Oracle 就会分配一个新的块,这会产生行迁移( Row Migrating ),进行空间预留能够一定程度上保证数据库访问效率。 PCTUSED 也是用于设置一个百分比,当块中已使用的空间的比例小于这个百分比的时候,这个块才被标识为有效状态。只有有效的块才被允许插入数据。
2.2.3 PCTFREE,PCTUSED,及行链接(Row Chaining)
在手动管理的表空间(manually managed tablespaces)中,用户可以使用 PCTFREE 和 PCTUSED 这两个存储管理参数来控制对某段(segment)进行插入和更新操作时,如何利用属于此段的数据块(data block)中的可用空间。用户也可以在创建或修改索引时为其设定 PCTFREE 参数(索引存储在索引段(index segment)中)。
提示:本节的内容并不适用于 LOB 数据类型(BLOB,CLOB,NCLOB,及 BFILE)。 这些类型的数据存储时不使用 PCTFREE 参数及可用块列表(free list)。
2.2.3.1 PCTFREE 参数
PCTFREE 参数用来设置一个数据块(data block)中至少需要保留(reserve)多少可用空间(百分比值),为数据块中已有数据更新时可能发生的数据量增长做准备。例如,当用户用 CREATE TABLE 语句创建表时指定了以下参数:PCTFREE 20
这个参数设定了此表对应的数据段(data segment)中的每个数据块(data block)至少保留20%的可用空间,以备块中已有数据更新时使用。只要数据块中行数据区与数据块头的容量之和不超过数据块总容量的80%,用户就可以向其中插入新数据,数据行被放入行数据区(row data area),相关信息被写入数据块头(overhead area)。
2.2.3.2PCTUSED 参数
PCTUSED 参数用于决定一个数据块(data block)是否可被用于插入新数据,她的依据是数据区(row data)与数据块头(overhead)的容量之和占数据块全部容量的最大百分比。当一个数据块中的可用空间比例小于 PCTFREE 参数的规定时,Oracle就认为此数据块无法被用于插入新数据,直到数据块中的占用容量比例小于 PCTUSED 参数的限定。在占用容量比例大于 PCTUSED 参数的限定之前,Oracle只在更新数据块内已有数据时才会使用此数据块的可用空间。例如,当用户用 CREATE TABLE 语句创建表时指定了以下参数:PCTUSED 40,当此表的某数据块占用容量比例高于40%时,Oracle不会将此数据块用于插入新数据行(假设此数据块的可用空间曾经低于 PCTFREE 的限定)。
2.2.3.4 PCTFREE 和 PCTUSED 如何协同发挥作用
PCTFREE 和 PCTUSED 共同作用可以优化数据块(data block)的空间使用。
PCTFREE 和 PCTUSED 如何共同作用以管理数据块(data block)可用空间的使用。
对于上述PCTFREE=20,PCTUSED=40的例子,oracle采用如下机制来管理数据块空间:
a.数据块占用空间比例小于80%时才能插入新数据,因为 PCTFREE 参数限定必须保留20%的可用空间用于块内已有数据的更新。
b.对数据块中已有数据的更新操作可以使用数据块中的保留空间。只有当数据块内的占用空间比例低于40%时才能向其中插入新数据。
c.当数据块内的占用空间比例低于40%时,此数据块再次可以被用于插入新数据。
d.数据块占用空间比例小于80%时才能插入新数据,因为 PCTFREE 参数限定必须保留20%的可用空间用于块内已有数据的更新。此过程如此往复循环。
在新分配的数据块中(data block),可用于插入(insert)数据的空间等于数据块总容量减去数据块头(block overhead)再减去预留可用空间(PCTFREE)。而更新(update)数据块内已有数据可使用数据块中的所有可用空间。因此,更新操作能够使数据块内的可用空间低于的 PCTFREE 限制,因为这些空间是专为更新操作而预留的。
在每个数据段(data segment)与索引段(index segment)中,Oracle管理着一个或多个可用块列表(free list)--其中列出了所有属于此段的数据扩展(extent),且可用空间比例大于 PCTFREE 限定的数据块。这些块可以被插入(insert)操作使用。当用户提交了 INSERT 语句后,Oracle从可用块列表中选择第一个有效的数据块使用。如果此数据块的可用空间不够容纳 INSERT 语句提交的数据,且此块的占用容量已经超过PCTUSED 的限定,Oracle就将其从可用块列表中移出。一个段可以同时使用多个可用块列表,以减少对一个表进行并发插入(concurrent insert)时产生的竞争。
当用户提交了 DELETE 或 UPDATE 语句后,Oracle处理语句并检查相关数据块中的占用空间比例是否小于 PCTUSED 的规定。如果满足,那么这个数据块就被放入当前事务(transaction)正在使用的可用块列表(free list)的头部,如果当前事务还需要写入数据,此块将被首先使用。当事务提交后,此数据块中的可用空间还可被其他事务使用。
2.3 数据扩展区概述
数据扩展区(extent)是由一组连续的数据块(data block)构成的数据库逻辑存储分配单位(一般由8个block组成)。而段(segment)则是由一个或多个数据扩展区构成。当一个段中已有空间已经用完,Oracle为这个段分配新的数据扩展区。
2.3.1 数据扩展何时被分配
当用户创建数据表时,Oracle为此表的数据段(data segment)分配一个包含若干数据块(data block)的初始数据扩展区(initial extent)。虽然此时数据表中还没有数据,但是在此初始数据扩展区中的数据块已经为插入新数据做好了准备。
如果一个段(segment)的初始数据扩展区(initial extent)中的数据块(data block)都已装满,且有新数据插入需要空间时,Oracle自动为这个段分配一个增量数据扩展区(incremental extent)。增量数据扩展区是一个段中继已有数据扩展区之后分配的后续数据扩展区,她的容量大于或等于之前的数据扩展区。
为了管理的需要,每个段(segment)的段头(header block)中包含一个记录此段所有数据扩展区(extent)的目录。