数据扩展(data extent)
数据扩展是为存储数据而分配的一组连续的数据块。段分配空间的时候总是以extent为单位来分配的。
在创建一个段时,指定一个initial extent,即初始数据扩展,当初始扩展中的数据块已经装满,且有新数据插入需要空间时,oracle将自动为这个段分配一个增量数据扩展,他的容量大于或者等于之前的数据扩展。每个段的段头包含记录此段所有数据扩展的目录。可以在创建段的时候定制初始扩展和增量扩展的值。
对于本地管理的表空间,在分配数据扩展时,首先选择一个属于此表空间的数据文件,然后再搜索此数据文件的位图(bitmap)查找连续的数据块(free blocks),如果此数据文件中没有足够的连续可用空间,oracle将查询其他数据文件。
一般来说,在用户将一个段(segment)对应的方案对象(schema object)移除(使用 DROP TABLE或 DROP CLUSTER语句)之前,此段的数据扩展(extent)不会被回收到表空间(tablespace)中,但是以下情况例外:
表,簇表的所有者(owner)或拥有 DELETE ANY权限的用户, 可以使用TRUNCATE...DROP STORAGE语句将表,簇表的数据清除
DBA可以使用以下语法收回一个段中未使用的数据扩展:ALTER TABLE table_name DEALLOCATE UNUSED;
如果用户为回滚段(rollback segment)设定了 OPTIMAL参数,Oracle将周期性地从其中回收数据扩展。
当数据扩展(extent)被释放后,Oracle修改数据文件(datafile)中的位图(bitmap)(对于本地管理的表空间)或更新数据字典(对于数据字典管理的表空间),将回收的数据扩展视为可用空间。被释放的数据扩展中的数据无法继续访问。
数据段(data segment)
段由一组数据扩展组成,这些数据扩展位于同一表空间中。Oracle为段分配空间的时候以数据扩展为单位,当段内已有的数据扩展没有可用空间时,oracle为此段分配一个新的数据扩展,一个段内的数据库扩展在磁盘上不一定是连续的。
一个段以及属于他的所有数据扩展必须包含在同一个表空间中,但是一个表空间内,一个段的数据扩展可以分布在多个数据文件上,即段可以跨文件存储,但是每个数据扩展只能包含于同一个数据文件中。
值得注意的是,在分配一个新的extent时,其中的数据块未必同时分配。如果用户是为某个数据库对象分配数据扩展 ,那么数据块也同时被立即分配并加入可用块列表(free list)中。如果数据扩展并非专为某数据库对象分配,那么数据块只在高水位线(high water mark)移动时才被分配。高水位线是段(segment)中已用和未用空间的边界。
用oracle concepts中的一个图来示意:
高水位标识(high water mark)
高水位线将一个段内的块划分为已使用块和空闲块,高水位以下的块中包含数据或者曾经包含数据而后被删除。oracle知道某个block内超出高水位线的位置并没有数据,所以全表扫描只读取块到高水位线。因此高水位对于全表扫描的性能有一定影响,后面将在性能调整一章具体来分析。Oracle在segment的segment header中记录段的high water mark。
一般的db操作中,高水位线只会上升,并不会下降,不过truncate可以降低高水位。也可以使用shrinking语句来降低高水位,回收空间。具体在空间管理中讲述。
对于table来说初始的高水位的位置总是在extent 0 block 0,而对于index来说实在extent 0 block 1。
Freelist,pctfree and pctused
当创建或者修改任何表或者索引时,oracle使用两个存储参数来进行空间控制。
Pctfree用来设置一个数据块内至少需要保留用于update现有数据的空间比例
Pctused块内数据区与数据块头的容量之和占数据块全部容量的最大百分比,用于决定一个数据块是否可被用于插入新数据,他的值决定了块是否返回到空闲链表(freelist)
Freelist oracle管理可用块的结构
当插入数据到块中时,Oracle首先在freelist中找到一个空闲块用以插入,这个快是否可用由pctfree的值决定,一个初始的空块将被加入空闲链表,空闲空间达到pctfree的值之前他会一直保持。
当空闲空间到达pctfree时,块将从freelist中去除,当数据块中的数据低于pctused值时再从新加入。
每次做插入操作之前,oracle只需要从freelist中查找空闲块来用于操作,而不是找找所有的块,因此freelist被用来提高插入性能。
行迁移(row migration)和行链接(row chaining)
数据块中行数据区包含了表或者索引的数据数据,一个数据行可以跨多个数据块。
行迁移
当update时,块内的空间不足以存放update后的值时,会引发行迁移,oracle将整行迁移到一个适合的新块,而原块中仅仅保存新块的rowid用来定位迁移后的行。
全表扫描的时候,转发地址将被忽略,因此行迁移对全表扫描没有影响,但索引读将会受到影响,将会有额外的io开销。我们知道索引读是通过rowid来查找行所在的文件号,块号和行,如果发生了行迁移,那么第一次找到的只是一个转发地址,还要再次io(逻辑io或者物理io)才能找到行。
行链接
一个单独的数据库块不能存放一个过大的行的时候,就会发生行链接。例如如果数据库使用4k的blocksize,将一个8k的行插入这个块,oralce将会使用3个block分开来存储这行,即发生行链接。
包含有long和long row的表常会发生行链接。
空闲空间管理(free space management)
空闲空间可以被手动或者自动管理,数据库中,每个段的可用空间可以被自动管理,段内的可用/已用空间以位图的形式记录,这与可用块以列表方式的管理不同。9i开始oracle推荐本地管理的表空间,即自动管理段内的可用空间。