必须先执行ALTER TABLE ... ENABLE ROW MOVEMENT,否则跨分区更新分区键会报ORA-14402;启用后UPDATE实际为删旧插新,触发器触发两次、全局索引失效需显式维护。
必须先执行 alter table ... enable row movement,否则任何跨分区更新分区键的操作都会直接报 ora-14402 ——这不是权限或语法问题,是 oracle 分区表的硬性约束。
为什么 UPDATE 分区键总报 ORA-14402
Oracle 默认禁止行在物理分区间“搬家”,哪怕你只是把 order_date 从 DATE'2023-12-31' 改成 DATE'2024-01-01',只要新值属于另一个分区,就触发拦截。报错信息 ORA-14402: updating partition key column would cause a partition change 就是明确告诉你:引擎拒绝执行这种重定位。
常见误判包括:
- 以为只改同一分区内的值就安全 —— 实际上 Oracle 不做运行时分区归属判断,一律拦截
- 试图用
INSERT ... SELECT+DELETE绕过 —— 逻辑等价但更难控制事务和触发器 - 查了索引、权限、拼写都没问题,却忽略表级
row_movement状态
如何安全启用 ENABLE ROW MOVEMENT
这是 DDL 操作,不是开关按钮,执行时会短暂持有 EXCLUSIVE 表锁。大表务必避开高峰。
操作前先确认状态:
SELECT table_name, row_movement FROM user_tables WHERE table_name = 'YOUR_TABLE_NAME';
启用命令很简单,但要注意:
- 必须有
ALTER权限,且不能在未提交事务上执行(会等待锁) - 不要加
NOLOGGING—— 虽然快,但破坏归档日志一致性,主备切换或闪回可能失败 - 如果表关联物化视图日志或 GoldenGate 复制,需提前验证下游兼容性
- 开启后不会立刻移动任何数据,只是“解禁”后续的
UPDATE
UPDATE 分区键的实际行为与副作用
开启 ENABLE ROW MOVEMENT 后,UPDATE 看似正常,但底层是「删除旧行 + 插入新行」,不是原地修改。
这意味着:
- 触发器会触发两次:
BEFORE UPDATE和AFTER UPDATE各一次,:OLD/:NEW值分别对应迁移前后 - 主键/唯一约束检查延迟到插入阶段,原本被掩盖的冲突可能突然暴露
- 高水位线(HWM)可能上升,尤其批量更新时易造成空间浪费
- 本地索引自动维护;但全局索引会变成
UNUSABLE,必须显式加UPDATE GLOBAL INDEXES才保持有效
示例(范围分区表 sales):
UPDATE sales SET sale_date = DATE'2025-04-01' WHERE id = 12345;
若原 sale_date 属于 2025-03 分区,新值属 2025-04 分区,则该行物理迁移到新分区段,ROWID 变更。
全局索引失效这个点最容易被忽略
很多人开了 ENABLE ROW MOVEMENT、跑通 UPDATE,一查数据发现查询变慢甚至报错 —— 很大概率是全局索引已失效,但没人去查 dba_indexes.status。
执行完跨分区 UPDATE 后,务必检查:
SELECT index_name, status FROM user_indexes WHERE table_name = 'YOUR_TABLE_NAME';
若状态为 UNUSABLE,重建成本高;更稳妥的做法是在 UPDATE 语句里直接带上 UPDATE GLOBAL INDEXES 子句(Oracle 12c+ 支持):
UPDATE sales SET sale_date = DATE'2025-04-01' WHERE id = 12345 UPDATE GLOBAL INDEXES;
否则就得手动 ALTER INDEX ... REBUILD,期间索引不可用。


















