Oracle 在线重定义(DBMS_REDEFINITION)

Oracle 在线重定义(DBMS_REDEFINITION)

适用版本:Oracle Database 9i / 10g / 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07


1. 概述

在线重定义(DBMS_REDEFINITION) 允许在表保持在线可用的情况下修改结构[1]:

典型场景

  • 修改表结构(添加/删除列)
  • 修改分区策略
  • 修改存储属性
  • 重组表(消除碎片)
  • 修改约束

2. 在线重定义流程

1. 验证表是否可重定义
2. 创建中间表(新结构)
3. 启动重定义
4. 同步数据(可选)
5. 完成重定义
6. 删除中间表

3. 操作步骤

3.1 验证可重定义

-- 验证表是否可重定义
BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE(
    uname => 'scott',
    tname => 'employees',
    options_flag => DBMS_REDEFINITION.CONS_USE_PK
  );
END;
/

-- options_flag:
-- CONS_USE_PK: 使用主键
-- CONS_USE_ROWID: 使用 ROWID(无主键时)

3.2 创建中间表

-- 创建新结构的中间表
CREATE TABLE scott.employees_new (
  id NUMBER PRIMARY KEY,
  name VARCHAR2(100),
  salary NUMBER,
  dept_id NUMBER,
  create_time DATE DEFAULT SYSDATE
) TABLESPACE users
  PARTITION BY RANGE (create_time) (
    PARTITION p2026 VALUES LESS THAN (TO_DATE('2027-01-01','YYYY-MM-DD')),
    PARTITION p2027 VALUES LESS THAN (TO_DATE('2028-01-01','YYYY-MM-DD')),
    PARTITION pmax VALUES LESS THAN (MAXVALUE)
  );

3.3 启动重定义

BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE(
    uname => 'scott',
    orig_table => 'employees',
    int_table => 'employees_new',
    col_mapping => 'id id, name name, salary salary, dept_id dept_id, SYSDATE create_time',
    options_flag => DBMS_REDEFINITION.CONS_USE_PK
  );
END;
/

3.4 同步数据(可选)

-- 在重定义过程中同步增量数据
BEGIN
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
    uname => 'scott',
    orig_table => 'employees',
    int_table => 'employees_new'
  );
END;
/

3.5 复制依赖对象

-- 自动复制依赖对象(索引、约束、触发器等)
DECLARE
  num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
    uname => 'scott',
    orig_table => 'employees',
    int_table => 'employees_new',
    copy_indexes => DBMS_REDEFINITION.CONS_ORIG_PARAMS,
    copy_triggers => TRUE,
    copy_constraints => TRUE,
    copy_privileges => TRUE,
    ignore_errors => TRUE,
    num_errors => num_errors
  );
  DBMS_OUTPUT.PUT_LINE('Errors: ' || num_errors);
END;
/

-- 查看错误
SELECT object_name, base_table_name, ddl_txt 
FROM dba_redefinition_errors;

3.6 完成重定义

-- 完成重定义(短暂锁表)
BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE(
    uname => 'scott',
    orig_table => 'employees',
    int_table => 'employees_new'
  );
END;
/

3.7 清理

-- 删除中间表
DROP TABLE scott.employees_new PURGE;

4. 重定义选项

4.1 使用主键

options_flag => DBMS_REDEFINITION.CONS_USE_PK

4.2 使用 ROWID

-- 无主键时
options_flag => DBMS_REDEFINITION.CONS_USE_ROWID

4.3 列映射

-- 简单映射
col_mapping => 'id id, name name, salary salary'

-- 转换
col_mapping => 'id id, UPPER(name) name, salary*1.1 salary'

-- 添加新列
col_mapping => 'id id, name name, SYSDATE create_time'

5. 重定义分区表

5.1 非分区转分区

-- 中间表为分区表
CREATE TABLE scott.employees_new (...) 
  PARTITION BY RANGE (hire_date) (...);

-- 重定义
BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE(
    uname => 'scott',
    orig_table => 'employees',
    int_table => 'employees_new',
    col_mapping => NULL  -- 列名相同可省略
  );
END;
/

5.2 分区策略变更

-- 从 RANGE 转为 HASH
CREATE TABLE scott.employees_new (...)
  PARTITION BY HASH (id) PARTITIONS 8;

6. 监控重定义

6.1 查看进度

-- 查看重定义进度
SELECT 
  sid, 
  serial#, 
  opname, 
  target, 
  sofar, 
  totalwork,
  time_remaining
FROM v$session_longops
WHERE opname LIKE '%REDEFINITION%';

6.2 查看错误

SELECT * FROM dba_redefinition_errors;

6.3 查看对象

SELECT * FROM dba_redefinition_objects;

7. 中止重定义

-- 中止重定义
BEGIN
  DBMS_REDEFINITION.ABORT_REDEF_TABLE(
    uname => 'scott',
    orig_table => 'employees',
    int_table => 'employees_new'
  );
END;
/

-- 删除中间表
DROP TABLE scott.employees_new PURGE;

8. 多租户中的重定义

8.1 PDB 中重定义

-- 切换到 PDB
ALTER SESSION SET CONTAINER = hrpdb;

-- 执行重定义(同上)

9. 常见坑与排错

9.1 ORA-12091: 表不能在线重定义

修复

-- 1. 检查主键
SELECT constraint_name FROM dba_constraints 
WHERE table_name='EMPLOYEES' AND constraint_type='P';

-- 2. 使用 ROWID 模式
options_flag => DBMS_REDEFINITION.CONS_USE_ROWID

9.2 ORA-23539: 表正在重定义

修复

-- 1. 中止
BEGIN
  DBMS_REDEFINITION.ABORT_REDEF_TABLE(
    uname => 'scott',
    orig_table => 'employees',
    int_table => 'employees_new'
  );
END;
/

-- 2. 重新开始

9.3 复制依赖对象失败

修复

-- 1. 查看错误
SELECT * FROM dba_redefinition_errors;

-- 2. 手动创建
CREATE INDEX idx_emp_name ON scott.employees_new(name);

-- 3. 重新执行 COPY_TABLE_DEPENDENTS

9.4 性能问题

修复

-- 1. 在低峰期执行
-- 2. 使用并行
ALTER SESSION ENABLE PARALLEL DML;

-- 3. 分批同步
BEGIN
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE(...);
END;
/

9.5 物化视图日志残留

修复

-- 重定义完成后清理
DROP MATERIALIZED VIEW LOG ON scott.employees;

10. 最佳实践

  1. 生产用在线重定义:零停机
  2. 低峰期执行:减少影响
  3. 验证可重定义:CAN_REDEF_TABLE
  4. 使用主键模式:性能更好
  5. 分批同步:减少锁
  6. 复制依赖对象:保留索引约束
  7. 监控进度:v$session_longops
  8. 测试验证:先在测试库演练
  9. 保留中间表:应急回滚
  10. 完成后再清理:避免误删

11. 参考资料

[1] Oracle Database Administrator’s Guide 19c, “Online Table Redefinition” https://docs.oracle.com/en/database/oracle/oracle-database/19/admin/

[2] Oracle Database PL/SQL Packages and Types Reference 19c, “DBMS_REDEFINITION” https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/