数据块概述Oracle对数据库数据文件(datafile)中的存储空间进行管理的单位是数据块(data block)数据块是数据库中最小的(逻辑)数据单位与数据块对应的所有数据在操作系统级的最小物理存储单位是字节(byte)每种操作系统都有一个被称为块容量(block size)的参数Oracle每次获取数据时总是访问整个数(Oracle)数据块而不是按照操作系统块的容量访问数据
数据库中标准的数据块(data block)容量是由初始化参数 DB_BLOCK_SIZE 指定的除此之外用户还可以指定五个非标准的数据块容量(nonstandard block size)数据块容量应该设为操作系统块容量的整数倍(同时小于数据块容量的最大限制)以便减少不必要的I/O操作Oracle数据块是Oracle可以使用和分配的最小存储单位
另见针对特定操作系统的Oracle文档中包含更多有关数据块容量(data block size)的信息多种数据块容量(Multiple Block Sizes)
数据块结构在Oracle中不论数据块中存储的是表(table)索引(index)或簇表(clustered data)其内部结构都是类似的图 说明了数据块的结构
本图显示了数据块的各个组成部分包括数据块头(包括标准内容和可变内容)(common and variable header)表目录区(table directory)行目录区(row directory)可用空间区(free space)行数据区(row data)以下各节将分别讲解各个组成部分图中两个箭头表示一个数据块中的可用空间区的容量是可变的
数据块头(包括标准内容和可变内容)
数据块头(header)中包含了此数据块的概要信息例如块地址(block address)及此数据块所属的段(segment)的类型(例如表或索引)
表目录区如果一个数据表在此数据块中储存了数据行那么数据表的信息将被记录在数据块的表目录区(table directory)中
行目录区
此区域包含数据块中存储的数据行的信息(每个数据行片断(row piece) 在行数据区(row data area)中的地址)[一个数据块中可能保存一个完整的数据行也可能只保存数据行的一部分 所以文中使用row piece]
当一个数据块(data block)的行目录区(row directory)空间被使用后即使数据行被删除(delete)行目录区空间也不会被回收举例来说当一个曾经包含条记录的数据块被清空后其块头(header)的行目录区仍然占用字节(byte)的空间只有在数据块中插入(insert)新数据时行目录区空间才会被 重新利用
管理开销数据块头(data block header)表目录区(table directory)行目录区(row directory)被统称为管理开销(overhead)其中 有些开销的容量是固定的而有些开销的总容量是可变的数据块中固定及可变管理开销的容量平均在到字节(byte)之间
行数据数据块(data block)中行数据区(row data)包含了表或索引的实际数据一个数据行可以跨多个数据块这就出现了行链接(Row Chaining)及行迁移(Row Migrating)
可用空间区在插入新数据行或在更新数据行需要更多空间时(例如原来某行最后一个字段为空(trailing null)现在要更新为非空值)将 使用可用空间区(free space)中的空间
如果一个数据块(data block)属于表或簇表的数据段(data segment)或属于索引的索引段(index segment)那么在其可用空间区中还可能会存储事务条目(transaction entry)如果一个数据块中的数据行(row)正在由 INSERTUPDATEDELETE及 SELECT……FOR UPDATE 语句访问此数据块中就需要保存事务条目事务条目所需的存储空间依据操作系统而定在常见的操作系统中事务条目大约需要有两种SQL语句可以增加数据块中的可用空间分别是 DELETE 语句和将现有数据值更新为占用容量更小值的 UPDATE 语句在以下两种条件下上述两中操作释放的空间可以被后续的 INSERT 语句使用
如果 INSERT 语句与上述两种操作在同一事务(transaction)中且位于释放空间的语句之后那么 INSERT 语句可以使用被释放的空间
如果 INSERT 语句与释放空间的语句在不同的事务中(比如两者是由不同的用户提交的)那么只有在释放空间的语句提交后且插入数据必需使用此数据块时INSERT 语句才会使用被释放的空间
数据块(data block)中被释放出的空间未必与可用空间区(free space)相连续Oracle在满足以下条件时才会将释放的空间合并到可用空间区()INSERT 或 UPDATE 语句选中了一个有足够可用空间容纳新数据的数据块()但是此块中的可用空间不连续数据无法被写入到数据块中连续的空间里Oracle只在 满足上述条件时才对数据块中的可用空间进行合并这样做是为了避免过于频繁的空间合并工作影响数据库性能
占用 行链接(Row Chaining)及行迁移(Row Migrating)
有两种情况会导致表中某行数据过大一个数据块(data block)无法容纳第一种情况当一行数据被插入时一个数据块就无法容纳在这种情况下Oracle将这行数据存储在段内的一个数据块链(chain)中在插入数据量大的行时常会发生行链接(row chaining)例如一个包含数据类型为 LONG 或 LONG RAW 列的数据行此时行链接不可避免
第二种情况原本存储在一个数据块(data block)内的数据行因为更新操作导致长度增长而所在数据块的可用空间也不能容纳增长后的数据行在这种情况下Oracle将此行数据迁移(migrate)到新的数据块中Oracle在被迁移数据行原来所在位置保存一个指向新数据块的指针被迁移数据行的 rowid 保持不变
当数据行发生链接(chain)或迁移(migrate)时对其访问将会造成 I/O 性能降低因为Oracle为获取这些数据行的数据时必须访问更多的数据块(data block)
另见 数据行结构与长度了解关于数据行结构的信息 数据行的 Rowid了解关于 rowid 的信息 物理 Rowid了解关于 rowid 的信息Oracle Database Performance Tuning Guide 了解如何减少行链接与行迁移以便提高系统I/O性能字节(byte)
PCTFREEPCTUSED及行链接(Row Chaining)
在手动管理的表空间(manually managed tablespaces)中用户可以使用 PCTFREE 和 PCTUSED 这两个存储管理参数来控制对某段(segment)进行插入和更新操作时如何利用属于此段的数据块(data block)中的可用空间用户也可以在创建或修改索引时为其设定 PCTFREE 参数(索引存储在索引段(index segment)中)
提示
本节的内容并不适用于 LOB 数据类型(BLOBCLOBNCLOB及 BFILE) 这些类型的数据存储时不使用 PCTFREE 参数及可用块列表(free list)
PCTFREE 参数PCTFREE 参数用来设置一个数据块(data block)中至少需要保留(reserve)多少可用空间(百分比值)为数据块中已有数据更新时可能发生的数据量增长做准备例如当用户用 CREATE TABLE 语句创建表时指定了以下参数PCTFREE 这个参数设定了此表对应的数据段(data segment)中的每个数据块(data block)至少保留%的可用空间以备块中已有数据更新时使用只要数据块中行数据区与数据块头的容量之和不超过数据块总容量的%用户就可以向其中插入新数据数据行被放入行数据区(row data area)相关信息被写入数据块头(overhead area)图 说明了 PCTFREE 的作用
PCTUSED 参数PCTUSED 参数用于决定一个数据块(data block)是否可被用于插入新数据她的依据是数据区(row data)与数据块头(overhead)的容量之和占数据块全部容量的最大百分比当一个数据块中的可用空间比例小于 PCTFREE 参数的规定时Oracle就认为此数据块无法被用于插入新数据直到数据块中的占用容量比例小于 PCTUSED 参数的限定在占用容量比例大于 PCTUSED 参数的限定之前Oracle只在更新数据块内已有数据时才会使用此数据块的可用空间例如当用户用 CREATE TABLE 语句创建表时指定了以下参数PCTUSED 在例子中当此表的某数据块占用容量比例高于%时Oracle不会将此数据块用于插入新数据行(假设此数据块的可用空间曾经低于 PCTFREE 的限定)图 说明了 PCTUSED 的作用
PCTFREE 和 PCTUSED 如何协同发挥作用PCTFREE 和 PCTUSED 共同作用可以优化数据块(data block)的空间使用
PCTFREE 和 PCTUSED 如何共同作用以管理数据块(data block)可用空间的使用
在第一步中数据块占用空间比例小于%时才能插入新数据因为 PCTFREE 参数限定必须保留%的可用空间用于块内已有数据的更新
在第二步中对数据块中已有数据的更新操作可以使用数据块中的保留空间只有当数据块内的占用空间比例低于%时才能向其中插入新数据
在第三步中当数据块内的占用空间比例低于%时此数据块再次可以被用于插入新数据
在第四步中数据块占用空间比例小于%时才能插入新数据因为 PCTFREE 参数限定必须保留%的可用空间用于块内已有数据的更新此过程如此往复循环
在新分配的数据块中(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)的头部如果当前事务还需要写入数据此块将被首先使用当事务提交后此数据块中的可用空间还可被其他事务使用
数据扩展概述数据扩展(extent)是由一组连续的数据块(data block)构成的数据库逻辑存储分配单位而段(segment)则是由一个或多个数据扩展构成当一个段中已有空间已经用完Oracle为这个段分配新的数据扩展
数据扩展何时被分配当用户创建数据表时Oracle为此表的数据段(data segment)分配一个包含若干数据块(data block)的初始数据扩展(initial extent)虽然此时数据表中还没有数据但是在此初始数据扩展中的数据块已经为插入新数据做好了准备
如果一个段(segment)的初始数据扩展(initial extent)中的数据块(data block)都已装满且有新数据插入需要空间时Oracle自动为这个段分配一个增量数据扩展(incremental extent)增量数据扩展是一个段中继已有数据扩展之后分配的后续数据扩展她的容量大于或等于之前的数据扩展
为了管理的需要每个段(segment)的段头(header block)中包含一个记录此段所有数据扩展(extent)的目录