第一部分: 基础概念
PCTFREE 参数用来设置一个数据块(data block)中至少需要保留(reserve)
多少可用空间(百分比值),为数据块中已有数据更新时可能发生的数据量
增长做准备。例如,当用户用 CREATE TABLE 语句创建表时指定了以下参
数:
PCTFREE 20
这个参数设定了此表对应的数据段(data segment)中的每个数据块(data
block)至少保留20%的可用空间,以备块中已有数据更新时使用。只要数据
块中行数据区与数据块头的容量之和不超过数据块总容量的80%,用户就可
以向其中插入新数据,数据行被放入行数据区(row data area),相关信息被
写入数据块头(overhead area)。图 2-3 说明了 PCTFREE 的作用。
058 Figure 2-3 PCTFREE
图 2-3 PCTFREE

PCTUSED 参数用于决定一个数据块(data block)是否可被用于插入新数
据,她的依据是数据区(row data)与数据块头(overhead)的容量之和占数
据块全部容量的最大百分比。当一个数据块中的可用空间比例小于
PCTFREE 参数的规定时,Oracle就认为此数据块无法被用于插入新数据,直
到数据块中的占用容量比例小于 PCTUSED 参数的限定。在占用容量比例大
于 PCTUSED 参数的限定之前,Oracle只在更新数据块内已有数据时才会使用
此数据块的可用空间。例如,当用户用 CREATE TABLE 语句创建表时指定了
以下参数:
PCTUSED 40
在例子中,当此表的某数据块占用容量比例高于40%时,Oracle不会将此数据
块用于插入新数据行(假设此数据块的可用空间曾经低于 PCTFREE 的限
定)。图 2-4 说明了 PCTUSED 的作用。
图 2-4 PCTUSED

PCTFREE 和 PCTUSED 如何协同发挥作用
PCTFREE 和 PCTUSED 共同作用可以优化数据块(data block)的空间使用。
图 2-5 说明了这两种参数的交互作用。
图 2-5 使用 PCTFREE 和 PCTUSED 参数管理数据块的可用空间

上图说明了 PCTFREE 和 PCTUSED 如何共同作用以管理数据块
(data block)可用空间的使用。
在第一步中,数据块占用空间比例小于80%时才能插入新数据,因为
PCTFREE 参数限定必须保留20%的可用空间用于块内已有数据的更
新。
在第二步中,对数据块中已有数据的更新操作可以使用数据块中的保
留空间。只有当数据块内的占用空间比例低于40%时才能向其中插入
新数据。
在第三步中,当数据块内的占用空间比例低于40%时,此数据块再次
可以被用于插入新数据。
在第四步中,数据块占用空间比例小于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)的头
部,如果当前事务还需要写入数据,此块将被首先使用。当事务提交后,此
数据块中的可用空间还可被其他事务使用。
行链接(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)。
第二部分 Solution:
1) Analyze the table:
To prevent an ORA-1495 (specified chained row table not found), run the col owner_name format a10 select owner_name, table_name, head_rowid from chained_rows; 3) You can now eliminate the Migrated or Chained rows by Create Table A) Create an empty copy of the table that has the Migrated or Chained rows. CREATE TABLE B) Now delete the Migrated and Chained rows from the table. C) Insert the rows back to the table. INSERT INTO Truncate the chained_rows table and drop the temporary table. 一个对于行迁移数量巨大而且表记录数巨大的行迁移清除思路 by Metalink:ID 554366.1 http://lhyvsxman.itpub.net/post/38718/509360
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/12180666/viewspace-1042003/
,如需转载,请注明出处,否则将追究法律责任。
$ORACLE_HOME/rdbms/admin/utlchain.sql script.(@C:oracleproduct10.2.0db_1RDBMSADMINutlchain.sql;)
TRUNCATE TABLE CHAINED_ROWS:
ANALYZE TABLE LIST CHAINED ROWS;
BATCH OPERATION:
Select ' analyze table ' ||table_name ||' list chained rows into chained_rows; ' from dba_tables;
2) List the Migrated or Chained rows.
From SQL*Plus:
col table_name format a20
col head_rowid format a20
as Select (CTAS), exporting and then importing the table or by following
the next steps:
SELECT * FROM WHERE ROWID IN
(SELECT HEAD_ROWID FROM CHAINED_ROWS WHERE TABLE_NAME=');
DELETE FROM WHERE ROWID IN
(SELECT HEAD_ROWID FROM CHAINED_ROWS
WHERE TABLE_NAME='');
SELECT * FROM
Alternatively, you can move the table to a tablespace if the row cannot fit in the block and you need a tablespace with a larger block size:
alter table
Note: check the SQL Reference guide for your release, for details on the 'alter table..move..' command.
对于7*24小时的应用来说,down机的时间越长损失则越大,当然是要尽量的减短down机的时间。但是因为表本身比较大,不管怎样做什么操作都是会比较耗费时间和资源的,但是如果应用在某段时间内主要是以插入数据为主,更新数据和删除数据都很少的,因此可以考虑可以采用这么一种方法:先重命名表,然后重新建立一个和原来一样的表,用来保证之后的应用的数据是可以正常插入的,从而使应用不用停很久,因为重建一个没有任何数据的表结构的过程是很短暂的,大概需要几秒钟的时间,而重建好表了后就能保证应用能够正常的写入数据,从而使应用几乎不用停顿,然后把开始重命名的原始表按表模式导出,因为表的名字已经被改变,因此需要一个临时库来导入这些数据,然后重命名回原来的名字,然后按原来的表名导出后再重新导入原始数据库,这样操作起来虽然会比较麻烦,但是却是一种很有效很实际的方法,速度也很快,导出后导入,因为本身表结构已经建立好了,不需要其他任何的多的操作,而且最关键的是这种方法所需要的down机时间是最短的。
附:Robinson同学一次通过ASH诊断出Row chaining导致的I/O严重下降问题。