行迁移由UPDATE后行变长且原块剩余空间不足触发,Oracle将整行迁至新块并保留原块指针,导致二次I/O;PCTFREE在ASSM下仍控制块内更新预留空间,但需实测调整(如20%),迁移发生后须MOVE重建表才能修复。
直接结论:行迁移不是段空间不足引起的,而是数据块(block)内剩余空闲空间不足导致的;解决核心是释放单个块内的碎片、重组织行分布,而非扩大表空间或增加数据文件。
为什么 PCTFREE 设置过低会触发行迁移
Oracle 每个数据块预留的空闲空间由 PCTFREE 控制。当 UPDATE 使某行变长(比如 varchar2 字段从 'a' 扩到 'a...x1000'),而该块当前剩余空间 ROWID 不变,但访问需读两次块。
-
PCTFREE = 0极易触发迁移(尤其在批量 update 后) -
PCTFREE = 10对中等更新频率的表常不够用,建议设为 15–25 - 注意:
PCTFREE只影响新插入/更新行为,对已迁移的行无效
如何确认是否真有行迁移(而非行链接)
先运行 ANALYZE TABLE ... LIST CHAINED ROWS,再查 CHAINED_ROWS 表。但关键点在于:CHAIN_CNT 是迁移 + 链接的总和,不能直接区分。必须结合表结构判断:
- 如果表含
LONG、LOB、超长VARCHAR2(如 4000 字节放 2KB 块里),CHAIN_CNT > 0很可能是行链接(row chaining),无法靠MOVE解决 - 如果表只有普通类型(
NUMBER、VARCHAR2(200)等),且近期执行过大规模UPDATE,那大概率是行迁移 - 查
DBA_TABLES.CHAIN_CNT后,再执行SELECT COUNT(*) FROM CHAINED_ROWS WHERE TABLE_NAME = 'T' AND HEAD_ROWID IS NOT NULL—— 有结果即确认存在迁移
ALTER TABLE ... MOVE 是最常用且有效的修复手段
它会重新分配所有行到新块中,自然消除迁移。但要注意副作用:
- 执行期间表被独占锁定(DDL 锁),DML 全部阻塞
- 所有索引变为
UNUSABLE,必须显式ALTER INDEX ... REBUILD - 不保留原表的物理属性(如
INITRANS、STORAGE参数),需手动指定或重建时加回 - 示例:
ALTER TABLE cust_dimt0 MOVE PCTFREE 20; ALTER INDEX cust_dimt0_pk REBUILD;
生产环境绕过锁表的替代方案
如果不能停业务,MOVE 不可行,可考虑以下路径:
- 用
DBMS_REDEFINITION在线重定义:支持主外键、索引、约束,但要求有足够临时空间,且过程较复杂 - 分批
UPDATE+DELETE+INSERT:仅适用于能容忍短暂逻辑不一致的场景,且需处理并发更新风险 - 添加新列带默认值会加剧迁移(尤其大数据量表),绝对避免在高峰期执行
ALTER TABLE ... ADD COLUMN DEFAULT ... - 真正容易被忽略的是:迁移修复后若不调高
PCTFREE或改用 ASSM 表空间,很快又会复发


















