Oracle数据块原理深入剖析

数据块(Oracle Data Blocks),本文简称为“块”,是Oracle最小的存储单位,Oracle数据存放在“块”中。一个块占用一定的磁盘空间。特别注意的是,这里的“块”是Oracle的“数据块”,不是操作系统的“块”。

Oracle每次请求数据的时候,都是以块为单位。也就是说,Oracle每次请求的数据是块的整数倍。如果Oracle请求的数据量不到一块,Oracle也会读取整个块。所以说,“块”是Oracle读写数据的最小单位或者最基本的单位。

块的标准大小由初始化参数DB_BLOCK_SIZE指定。具有标准大小的块称为标准块(Standard Block)。块的大小和标准块的大小不同的块叫非标准块(Nonstandard Block)。同一数据库中,Oracle9i及以上版本支持同一数据库中同时使用标准块和非标准块。Oracle允许指定5种非标准块(Nonstandard Block)。

操作系统每次执行I/O的时候,是以操作系统的块为单位;Oracle每次执行I/O的时候,都是以Oracle的块为单位。
Oracle数据块大小一般是操作系统块的整数倍。

数据块的格式(Data Block Format)

块中存放表的数据和索引的数据,无论存放哪种类型的数据,块的格式都是相同的,块由块头(header/Common and Variable),表目录(Table Directory),行目录(Row Directory),空余空间(Free Space)和行数据(Row Data)五部分组成,
如下图所示。 

 

块头(header/Common and Variable):存放块的基本信息,如:块的物理地址,块所属的段的类型(是数据段还是索引段)。 表目录(Table Directory):存放表的信息,即:如果一些表的数据被存放在这个块中,那么,这些表的相关信息将被存放在“表目录”中。

行目录(Row Directory):如果块中有行数据存在,则,这些行的信息将被记录在行目录中。这些信息包括行的地址等。

行数据(Row Data):是真正存放表数据和索引数据的地方。这部分空间是已被数据行占用的空间。

空余空间(Free Space):空余空间是一个块中未使用的区域,这片区域用于新行的插入和已经存在的行的更新。

头部信息区(Overhead):我们把块头(header/Common and Variable),表目录(Table Directory),行目录(Row Directory)这三部分合称为头部信息区(Overhead)。头部信息区不存放数据,它存放的整个块的信息。头部信息区的大小是可变的。一般来说,头部信息区的大小介于84字节(bytes)到107字节(bytes)之间。

数据块中自由空间的使用

当往数据库中插入(INSERT)数据的时候,块中的自由空间会减少;当对块中已经存在的行进行修改(UPDATE)的时候(使记录长度增加),块中的自由空间也会减少。

DELETE语句和UPDATE语句会使块中的自由空间增加。当使用DELETE语句删除块中的记录或者使用UPDATE语句把列的值更改成一个更小值的时候,Oracle会释放出一部分自由空间。释放出的自由空间并不一定是连续的。通常情况下,Oracle不会对块中不连续的自由空间进行合并。因为合并数据块中不连续的自由空间会影响数据库的性能。只有当用户进行数据插入(INSERT)或者更新(UPDATE)操作,却找不到连续的自由空间的时候,Oracle才会合并数据块中不连续的自由空间。

对于块中的自由空间,Oracle提供两种管理方式:自动管理,手动管理

行链接和行迁移(Row Chaining and Migrating)

行链接(Row Chaining):如果我们往数据库中插入(INSERT)一行数据,这行数据很大,以至于一个数据块存不下一整行,Oracle就会把一行数据分作几段存在几个数据块中,这个过程叫行链接(Row Chaining)。如下图所示: 

 


如果一行数据是普通行,这行数据能够存放在一个数据块中;如果一行数据是链接行,这行数据存放在多个数据块中。

行迁移(Row Migrating):数据块中存在一条记录,用户执行UPDATE更新这条记录,这个UPDATE操作使这条记录变长,这时候,Oracle在这个数据块中进行查找,但是找不到能够容纳下这条记录的空间,无奈之下,Oracle只能把整行数据移到一个新的数据块。原来的数据块中保留一个“指针”,这个“指针”指向新的数据块。被移动的这条记录的ROWID保持不变。行迁移的原理如下图所示: 

 

无论是行链接还是行迁移,都会影响数据库的性能。Oracle在读取这样的记录的时候,Oracle会扫描多个数据块,执行更多的I/O。

块中自由空间的自动管理

Oracle使用位图(bitmap)来管理和跟踪数据块,这种块的空间管理方式叫“自动管理”。自动管理有下面的好处:

◆易于使用

◆更好地利用空间

◆可以对空间进行实时调整

块中自由空间的手动管理

用户可以通过PCTFREE, PCTUSED来调整块中空间的使用,这种管理方式叫手动管理。相对于自动管理,手动管理方式比较麻烦,不容易掌握,容易造成块中空间的浪费。

PCTFREE参数用于指定块中必须保留的最小空闲空间百分例。之所以要预留这样的空间,是因为UPDATE时,需要这些空间。如果UPDATE时,没有空余空间,Oracle就会分配一个新的块,这会产生行迁移(Row Migrating)。
PCTUSED也是用于设置一个百分比,当块中已使用的空间的比例小于这个百分比的时候,这个块才被标识为有效状态。只有有效的块才被允许插入数据。




Oracle存储数据的最小粒度(finest level of granularity)被称为数据块(data block)(也叫做逻辑块(logical block),Oracle块(Oracle block)或页(page))。一个数据块对应于磁盘上数个字节(byte)的物理数据库空间。 
  
  处于数据块之上的逻辑数据库空间是数据扩展(extent)。数据扩展是为存储数据而分配的一组连续的数据块。 
  
  位于数据扩展之上的逻辑数据库存储结构是段(segment)。段由一组数据扩展 (extent)构成,这些数据扩展位于同一表空间(tablespace)中,用于存储各种逻辑数据结构。例如每个表(table)的数据都存储在其自身的数据段(data segment)中,每个索引(index)的数据都存储在其自身的索引段(index segment)中。如果表或索引是分区存储(partitioned)的,则每个分区拥有自己的段。 
  
  Oracle为段(segment)分配空间时以数据扩展(extent)为单位。当段内已有的数据扩展没有可用空间时,Oracle为此段分配一个新的数据扩展。因为数据扩展是随需分配的,所以一个段内的数据扩展在磁盘上未必是连续的。 
  
  一个段(segment)以及属于她的所有数据扩展(extent)必须包含在同一表空间中。但在一个表空间内,属于同一个段的数据扩展可以分布在多个数据文件(datafile)上,即段可以跨文件存储。但是每个数据扩展只能包含于同一个数据文件中。 
  
  在用户分配一个新的数据扩展(extent)时,其中的数据块(data block)未必被同时分配。如果用户是为某个数据库对象分配数据扩展 ,那么数据块也同时被立即分配并加入可用块列表(free list)中。如果数据扩展并非专为某数据库对象分配,那么数据块只在高水位线 (high water mark)移动时才被分配。高水位线是段(segment)中已用和未用空间的边界。 
  
  数据块概述 
  
  
  Oracle对数据库数据文件(datafile)中的存储空间进行管理的单位是数据块(data block)。数据块是数据库中最小的(逻辑)数据单位。与数据块对应的,所有数据在操作系统级的最小物理存储单位是字节(byte)。每种操作系统都有一个被称为块容量(block size)的参数。Oracle每次获取数据时,总是访问整数个(Oracle)数据块,而不是按照操作系统块的容量访问数据。 
  
  数据库中标准的数据块(data block)容量是由初始化参数 DB_BLOCK_SIZE 指定的。除此之外,用户还可以指定五个非标准的数据块容量(nonstandard block size,在10g R2 32bit版本中可以指定2k,4k,16k,32k四个非标准数据块容量)。数据块容量应该设为操作系统块容量的整数倍(同时小于数据块容量的最大限制),以便减少不必要的I/O操作。Oracle的数据块是Oracle可以使用和分配的最小存储单位。 
  
  数据块结构 
  
  在Oracle中,不论数据块中存储的是表(table)、索引(index)或簇表(clustered data),其内部结构都是类似的。
  标准内容:数据块头中包含了此数据块的概要信息,例如块地址(block address)及此数据块所属的段(segment)的类型,例如,表或索引,该部分为。可变内容:ITL(Interested Transaction List)用来记录该块所有发生的事务,一个itl可以看作是一个记录,在一个时间,可以记录一个事务(包括提交或者未提交事务)。当然,如果这个事务已经提交,那么这个itl的位置就可以被反复使用了,因为itl类似记录,所以,有的时候也叫itl槽位。 如果一个事务一直没有提交,那么,这个事务将一直占用一个itl槽位,itl里面记录了事务信息,回滚段的入口,事务类型等等。如果这个事务已经提交,那么,itl槽位中还保存的有这个事务提交时候的SCN号。 
  
  表目录区 
  
  如果一个数据表在此数据块中储存了数据行,那么数据表的信息将被记录在数据块的表目录区(table directory)中。 
  
  行目录区 
  
  此区域包含数据块中存储的数据行的信息(每个数据行片断(row piece) 在行数据区(row data area)中的地址)。 (一个数据块中可能保存一个完整的数据行,也可能只保存数据行的一部分 ,所以文中使用row piece) 
  
  当一个数据块(data block)的行目录区(row directory)空间被使用后,即使数据行被删除(delete),行目录区空间也不会被回收。举例来说,当一个曾经包含50条记录的数据块被清空后,其块头(header)的行目录区仍然占用100字节(byte)的空间。只有在数据块中插入(insert)新数据时,行目录区空间才会被重新利用。
  
  管理开销 
  
  数据块头(data block header),表目录区(table directory),行目录区(row directory)被统称为管理开销。其中 有些开销的容量是固定的;而有些开销的总容量是可变的(ITL)。数据块中固定及可变管理开销的容量平均在84到107字节(byte)之间。 
  
  行数据 
  
  数据块(data block)中行数据区(row data)包含了表或索引的实际数据。一个数据行可以跨多个数据块(是行链接和行迁移下文会讲到) 
  
  可用空间 
  
  在插入新数据行,或在更新数据行需要更多空间时(例如,原来某行最后一个字段为空(trailing null),现在要更新为非空值),将使用可用空间区(free space)中的空间。 
  
  如果一个数据块(data block)属于表或簇表的数据段(data segment),或属于索引的索引段(index segment),那么在其数据块头中还可能会存储事务条目 。如果一个数据块中的数据行正在由 INSERT, UPDATE, DELETE,及 SELECT...FOR UPDATE 语句访问,此数据块中就需要保存事务条目。 
  
  事务条目所需的存储空间依据操作系统而定。在常见的操作系统中事务条目大约需要占用23字节(byte)。 
  
  数据块中的可用空间管理 
  
  数据库中段的管理方式决定了数据块中可用空间的管理方式。的可用空间可以被自动管理。段内的可用/已用空间以位图(bitmap)形式记录(自动管理模式下),这与手动管理采用free list以列表方式的管理不同。段空间自动管理(Automatic segment-space management)具备以下优势: 
  
  1、空间利用效率更高,尤其针对每行数据容量差异大的表(或其他对象) 
  
  2、能够更好地针对当前数据的情况实时调整 
  
  3、易于使用 
  
  4、在RAC环境下能更好的提升性能和空间利用(个人认为是因为第一和第二点的优势在RAC环境下能更明显的体现出来的原因。) 
  
  用户可以在创建一个本地管理的表空间(locally managed tablespace)时选择自动段空间管理(automatic segment-space management)功能。这样在此表空间内创建的段都将默认地设置为自动段空间管理。 
  
  数据块可用空间的有效性及优化 
  
  有两种SQL语句可以增加数据块中的可用空间:分别是 DELETE 语句,和将现有数据值更新为占用容量更小值的 UPDATE 语句。在以下两种条件下,上述两中操作释放的空间可以被后续的 INSERT 语句使用: 
  
  如果 INSERT 语句与上述两种操作在同一事务(transaction)中,且位于释放空间的语句之后,那么 INSERT 语句可以使用被释放的空间。 
  
  如果 INSERT 语句与释放空间的语句在不同的事务中(比如两者是由不同的用户提交的),那么只有在释放空间的语句提交后,且插入数据必需使用此数据块时, INSERT 语句才会使用被释放的空间。 
  
  数据块(data block)中被释放出的空间未必与可用空间区(free space)相连续。Oracle在满足以下条件时才会将释放的空间合并到可用空间区:(1) INSERT 或 UPDATE 语句选中了一个有足够可用空间容纳新数据的数据块,(2)但是此块中的可用空间不连续,数据无法被写入到数据块中连续的空间里。Oracle只在 满足上述条件时才对数据块中的可用空间进行合并,这样做是为了避免过于频繁的空间合并工作影响数据库性能。 
  
  数据块中行片段 
  
  Oracle 使用一个或多个行片断(row piece)来存储表的每一行数据的前255列。当一个数据块(data block)可以容纳一个完整的数据行时(且表的列数小于等于 256),那么此行就可以使用一个行片断来存储。当插入(insert)一个数据行,或更新(update)已有数据行时,数据行容量大于数据块容量,那么 Oracle 将使用多个行片断来存储此行。大多数情况下,每个数据行只存储于一个行片断中,且在同一数据块内。 
  
  有两种情况会导致表中某行数据过大,一个数据块(data block)无法容纳。 
  
  第一种情况,行链接 
  
  当一行数据被插入时一个数据块就无法容纳 。在这种情况下Oracle将这行数据存储在段内的一个数据块链(chain)中。在插入数据量大的行时常会发生行链接(row chaining),例如一个包含数据类型为 LONG 或 LONG RAW 列的数据行。此时行链接不可避免。当 Oracle 必须使用多个行片断来存储同一数据行时(且每个行片断位于不同的数据块内),此行将在多个数据块间构成行链接(Row Chaining)。 
  
  当一个表超过 255 列时,每行第255列之后的数据将作为一个新的行片断(row piece)存储在相同的数据块(data block)中,这被称为块内链接(intra-block chaining)。由多个行片断组成的行进行块内链接时,使用各行片断的 rowid 进行链接。当一个行为块内链接时,用户可以从同一数据块中访问此行的全部数据。如果一个数据行位于同一数据块内,那么访问此行不会影响 I/O 性能,因为访问此行不会带来额外的 I/O 开销。 
  
  行迁移 
  
  原本存储在一个数据块(data block)内的数据行,因为更新操作导致长度增长,而所在数据块的可用空间也不能容纳增长后的数据行 。在这种情况下,Oracle将此行数据迁移到新的数据块中。Oracle在被迁移数据行原来所在位置保存一个指向新数据块的指针。被迁移数据行的 rowid 保持不变。 
  
  当数据行发生链接(chain)或迁移(migrate)时,对其访问将会造成 I/O 性能降低,因为Oracle为获取这些数据行的数据时,必须访问更多的数据块(data block)。 
  
  PCTUSED、PCTFREE 
  
  在手动管理的表空间(manually managed tablespaces)中,用户可以使用 PCTFREE 和 PCTUSED 这两个存储管理参数来控制对某段(segment)进行插入和更新操作时,如何利用属于此段的数据块(data block)中的可用空间。用户也可以在创建或修改索引时为其设定 PCTFREE 参数(索引存储在索引段(index segment)中)。 
  
  PCTFREE 
  
  PCTFREE 参数用来设置一个数据块(data block)中至少需要保留(reserve)多少可用空间(百分比值),为数据块中已有数据更新时可能发生的数据量增长做准备。例如,当用户用 CREATE TABLE 语句创建表时指定了以下参数: PCTFREE 20。 
  
  这个参数设定了此表对应的数据段(data segment)中的每个数据块(data block)至少保留20%的可用空间,以备块中已有数据更新时使用。只要数据块中行数据区与数据块头的容量之和不超过数据块总容量的80%,用户就可以向其中插入新数据,数据行被放入行数据区(row data area),相关信息被写入数据块头(overhead area)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值