分区表移动操作不会继承原分区空闲百分比,需显式指定以避免行迁移加剧。分析链行列表需逐个分区执行。移动后全局索引变为不可用需重建。大对象段需显式移动否则残留伪链行,导致持续的表提取连续行。
分区表做 MOVE 操作时,初衷通常是整理碎片、压缩空间或迁移表空间。但许多团队遇到的典型问题是:MOVE 完成后,行迁移(Row Migration)不仅没有消失,反而更加严重。根本原因在于 —— MOVE 属于物理重写,默认按照当前行的实际长度紧凑写入新块,不会预留空闲空间。如果原分区由于 PCTFREE 设置不当已经产生了迁移行,这些行被一股脑塞进新块后,后续更新操作会立刻触发新的迁移,形成恶性循环。
MOVE 后反而出现行迁移?直接对分区执行 alter table ... move partition 本身并不能修复行迁移。关键在于 MOVE 不会继承原分区的 PCTFREE 设置(除非显式指定),而 ASSM 表空间下 PCTFREE 的作用机制又容易被忽略。这就像将萝卜一个挨一个紧凑存放,没有预留任何空间给未来的更新。
长期稳定更新的攒劲资源: >>>点此立即查看<<<

提前做好以下检查:
PCTFREE:SELECT partition_name, pct_free FROM user_tab_partitions WHERE table_name = 'TBL_NAME' AND partition_name = 'P1';MOVE 时必须显式指定 PCTFREE 参数,例如 ALTER TABLE tbl_name MOVE PARTITION p1 PCTFREE 20;COMPRESS FOR OLTP),MOVE 后需要重新启用,否则行宽膨胀更容易引发迁移ANALYZE TABLE ... LIST CHAINED ROWS 为何对分区表失效?该命令在分区表上存在隐藏的“盲区”——默认只分析分区键所在段的头部信息,不会扫描各个子分区的数据块。因此当迁移或链行集中在某个子分区时,CHAINED_ROWS 表可能完全为空,或者严重低估真实情况。
正确的做法是逐个分析具体分区:
@/rdbms/admin/utlchain.sql 创建了 CHAINED_ROWS 表ANALYZE TABLE tbl_name PARTITION(p1) LIST CHAINED ROWS INTO chained_rows;SELECT * FROM chained_rows WHERE table_name = 'TBL_NAME' AND partition_name = 'P1';还有一个容易混淆的地方:DBMS_STATS.GATHER_TABLE_STATS 不会报告链行,它只收集统计信息,无法替代 ANALYZE。
MOVE PARTITION 之后,本地索引(LOCAL)会自动维护,但全局索引(GLOBAL)会变成 UNUSABLE。更隐蔽的问题是:即使索引重建完毕,如果旧链行残留的块指针没有清理干净,某些查询依然会触发 table fetch continued row 等待事件,导致你误以为问题仍然存在。
SELECT index_name, status FROM user_indexes WHERE table_name = 'TBL_NAME';ALTER INDEX idx_name REBUILD;(不可用时必须加 REBUILD,不能只用 UPDATE INDEXES)SELECT name, value FROM v$sysstat WHERE name = 'table fetch continued row'; 对比 MOVE 前后的增量变化MOVE 触及的“伪链行”——最常见的就是 LOB 段没有同步移动,需要单独检查 USER_LOBS 并对 LOB 列执行 MOVEMOVE PARTITION 解决只要表里包含 CLOB 或 BLOB 字段,并且启用了 ENABLE STORAGE IN ROW(默认开启),Oracle 就有可能将大值存储在行外(OUT OF ROW)。此时 MOVE PARTITION 只移动了主表块,LOB 段依然留在原地——形成逻辑上的“跨块链接”,表现为持续的 table fetch continued row,但 CHAINED_ROWS 却查不到任何记录。
真正有效的做法分为两步:
SELECT column_name, in_row FROM user_lobs WHERE table_name = 'TBL_NAME';IN_ROW = 'NO',需要同步移动 LOB 段:ALTER TABLE tbl_name MOVE PARTITION p1 LOB(lob_col) STORE AS (TABLESPACE ts_name);ALTER TABLE tbl_name MODIFY LOB(lob_col) (DISABLE STORAGE IN ROW);,但这会额外增加一次 I/O 开销这个细节最容易被忽视:分区 MOVE 命令默认不包含 LOB 子句,必须显式声明。否则看似操作成功,实际上性能隐患已经悄悄埋下。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述