行迁移由UPDATE导致整行长度增大且超出块剩余空间引发,非主键列本身更新所致;IOT表更新主键则强制迁移并改变UROWID,而行链接是因行长超块容量被拆分存储。

UPDATE主键列本身不会直接触发行迁移
Oracle不允许直接UPDATE主键列(除非是IOT或启用了ROW MOVEMENT),否则会报错ORA-01442: column to be modified is null或违反约束。真正引发行迁移的,是UPDATE操作**连带导致整行长度显著增大**——比如主键列虽未变,但同一UPDATE语句中还更新了多个VARCHAR2字段,且新值比原值长很多,超出当前块剩余空闲空间(即PCTFREE预留空间)。
UPDATE主键列在IOT表中会强制行迁移
索引组织表(IOT)的主键就是物理存储顺序依据。一旦UPDATE主键值,该行必须重定位到B+树中新的键位置。此时:
- Oracle必须将整行数据迁移到新块(或新叶节点),原位置仅留转发指针;
-
ROWID失效,UROWID会变,所有依赖旧ROWID的缓存或应用逻辑可能出错; - 若IOT启用
OVERFLOW段,且更新后溢出列变大,还可能触发row chaining(行链接)。
为什么容易被误判为“UPDATE主键导致迁移”
常见混淆点在于:DBA看到UPDATE ... SET id = id, name = 'xxx'...这类语句(看似改主键实则没变),但实际执行时因绑定变量或NLS设置,name字段从'Alice'变成'Alice '(含空格)或字符集转换导致字节膨胀,最终整行长度超限。这时ANALYZE TABLE ... LIST CHAINED ROWS查出的迁移行,会被错误归因为“主键更新”。
验证方法:SELECT vsize(name), length(name) FROM employees WHERE rowid = 'AAABBB...';对比更新前后字节长度变化,而非只看字符数。
行溢出(chaining)和迁移(migration)在这里常同时出现
当UPDATE使行长大于单个块容量(如8KB),Oracle无法靠迁移解决——必须拆分存储,这就是行链接。它和行迁移的关键区别:
- 迁移:行仍是一整块,只是换了地方,
ROWID不变; - 链接:行被切成多片,分散在多个块,
ROWID指向首片,后续靠链式指针跳转; - 二者都会抬高
v$sysstat.name = 'table fetch continued row'计数,但修复方式不同:迁移可调PCTFREE或ALTER TABLE MOVE;链接只能改表结构(如拆LOB列、用COMPRESS BASIC)或加大db_block_size(不现实)。
最易被忽略的是:即使禁用ROW MOVEMENT,IOT表的主键UPDATE仍会强制迁移——这不是配置能绕过的机制限制。


















