Oracle 在线重定义

Oracle 在线重定义(Online Redefinition) 是一种功能,通过DBMS_REDEFINITION 包提供,允许DBA在不需要停止或显著影响数据库正常操作的情况下,对数据库表进行结构化修改。

可以实现的功能

  • 将表移动到其它表空间

  • 增加、修改或者删除表的字段

  • 将非分区表转换为分区表

  • 修改表的分区结构

  • 高水位线回收

  • 将普通表转换为索引组织表

测试数据

五千万条数据,数据文件test_tbs01.dbf,表空间test_tbs

将表移动到其它表空间

复制代码
#创建新表空间
CREATE TABLESPACE new_tbs DATAFILE '/datafile/new_tbs01.dbf' SIZE 10G AUTOEXTEND ON NEXT 1G MAXSIZE UNLIMITED;

#给用户授权
ALTER USER TEST_USER QUOTA UNLIMITED ON NEW_TBS;

#检查选择的表是否可以执行在线重定义
BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE('TEST_USER', 'TEST_TABLE');
END;
/

#创建中间表(结构与原表一致,但指定新表空间)
CREATE TABLE test_user.test_table_int (
    id NUMBER PRIMARY KEY,
    name VARCHAR2(100) NOT NULL,
    created_date DATE,
    value NUMBER(10),
    comments VARCHAR2(500)
) TABLESPACE new_tbs;

# 开始在线重定义(使用主键方式)
BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT',
    options_flag => DBMS_REDEFINITION.CONS_USE_PK  -- 使用主键
  );
END;
/

# 复制依赖对象(自动复制索引、约束)
DECLARE
  num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT',
    copy_indexes => DBMS_REDEFINITION.CONS_ORIG_PARAMS,
    copy_triggers => TRUE,
    copy_constraints => TRUE,
    copy_privileges => TRUE,
    ignore_errors => TRUE,
    num_errors => num_errors
  );
END;
/

# 同步数据
BEGIN
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT'
  );
END;
/

# 完成重定义(短暂锁表)

# DBMS_REDEFINITION.FINISH_REDEF_TABLE 会执行flush shard pool 需要规避
alter session set events '10995 trace name context forever, level 2';

BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT'
  );
END;
/

增加、修改或者删除表的字段

操作:添加字段new_column VARCHAR2(50),删除字段comments。

复制代码
#检查选择的表是否可以执行在线重定义
BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE('TEST_USER', 'TEST_TABLE');
END;
/
复制代码
# 创建中间表(添加新字段,删除旧字段)
CREATE TABLE test_user.test_table_int (
    id NUMBER PRIMARY KEY,
    name VARCHAR2(100) NOT NULL,
    created_date DATE,
    value NUMBER(10),
    new_column VARCHAR2(50)
) TABLESPACE test_tbs;
复制代码
# 开始在线重定义(使用主键方式)
BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE(
    uname        => 'TEST_USER', 
    orig_table   => 'TEST_TABLE',
    int_table    => 'TEST_TABLE_INT',
    col_mapping  => 'id id, name name, created_date created_date, value value', 
    options_flag => DBMS_REDEFINITION.CONS_USE_PK
  );
END;
/
复制代码
# 复制依赖对象(自动复制索引、约束)
DECLARE
  num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT',
    copy_indexes => DBMS_REDEFINITION.CONS_ORIG_PARAMS,
    copy_triggers => TRUE,
    copy_constraints => TRUE,
    copy_privileges => TRUE,
    ignore_errors => TRUE,
    num_errors => num_errors
  );
END;
/

# 同步数据
BEGIN
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT'
  );
END;
/
复制代码
# 完成重定义
BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT'
  );
END;
/

将非分区表转换为分区表

复制代码
#检查选择的表是否可以执行在线重定义
BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE('TEST_USER', 'TEST_TABLE');
END;
/
复制代码
#创建中间表
CREATE TABLE test_user.test_table_int (
    id            NUMBER,
    name          VARCHAR2(100) NOT NULL,
    created_date  DATE NOT NULL, 
    value         NUMBER(10),
    new_column    VARCHAR2(50),
    CONSTRAINT pk_test_table_int PRIMARY KEY (id, created_date) 
)
PARTITION BY RANGE (created_date) (
    PARTITION p1 VALUES LESS THAN (TO_DATE('2023-01-01', 'YYYY-MM-DD')),
    PARTITION p2 VALUES LESS THAN (TO_DATE('2024-01-01', 'YYYY-MM-DD')),
    PARTITION p3 VALUES LESS THAN (MAXVALUE)
) TABLESPACE test_tbs;
复制代码
# 开始在线重定义(使用主键方式)
BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE(
    uname        => 'TEST_USER',
    orig_table   => 'TEST_TABLE',
    int_table    => 'TEST_TABLE_INT',
    col_mapping  => 'id id, 
                     name name, 
                     created_date created_date, 
                     value value, 
                     new_column new_column',  
    options_flag => DBMS_REDEFINITION.CONS_USE_PK
  );
END;
/
复制代码
-- 复制依赖对象(自动复制索引、约束)
DECLARE
  num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT',
    copy_indexes => DBMS_REDEFINITION.CONS_ORIG_PARAMS,
    copy_triggers => TRUE,
    copy_constraints => TRUE,
    copy_privileges => TRUE,
    ignore_errors => TRUE,
    num_errors => num_errors
  );
END;
/
复制代码
# 同步数据
BEGIN
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT'
  );
END;
/
复制代码
# 完成重定义

# DBMS_REDEFINITION.FINISH_REDEF_TABLE 会执行flush shard pool 需要规避
alter session set events '10995 trace name context forever, level 2';

BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT'
  );
END;
/
复制代码
#创建新表空间
CREATE TABLESPACE new_tbs DATAFILE '/datafile/new_tbs01.dbf' SIZE 10G AUTOEXTEND ON NEXT 1G MAXSIZE UNLIMITED;

#给用户授权
ALTER USER TEST_USER QUOTA UNLIMITED ON NEW_TBS;

#检查选择的表是否可以执行在线重定义
BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE('TEST_USER', 'TEST_TABLE');
END;
/

#创建中间表(结构与原表一致,但指定新表空间)
CREATE TABLE test_user.test_table_int (
    id NUMBER PRIMARY KEY,
    name VARCHAR2(100) NOT NULL,
    created_date DATE,
    value NUMBER(10),
    comments VARCHAR2(500)
) TABLESPACE new_tbs;

# 开始在线重定义(使用主键方式)
BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT',
    options_flag => DBMS_REDEFINITION.CONS_USE_PK  -- 使用主键
  );
END;
/

-- 复制依赖对象(自动复制索引、约束)
DECLARE
  num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT',
    copy_indexes => DBMS_REDEFINITION.CONS_ORIG_PARAMS,
    copy_triggers => TRUE,
    copy_constraints => TRUE,
    copy_privileges => TRUE,
    ignore_errors => TRUE,
    num_errors => num_errors
  );
END;
/

# 同步数据
BEGIN
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT'
  );
END;
/

# 完成重定义(短暂锁表)

# DBMS_REDEFINITION.FINISH_REDEF_TABLE 会执行flush shard pool 需要规避
alter session set events '10995 trace name context forever, level 2';

BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT'
  );
END;
/

修改表的分区结构

当前表为范围分区:

复制代码
# 创建哈希分区中间表

CREATE TABLE test_user.test_table_int (
    id            NUMBER,
    name          VARCHAR2(100) NOT NULL,
    created_date  DATE,
    value         NUMBER(10),
    new_column    VARCHAR2(50),
    CONSTRAINT pk_test_table_int PRIMARY KEY (id)
)
PARTITION BY HASH (id)
PARTITIONS 4
TABLESPACE test_tbs;
复制代码
# 启动在线重定义
BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE(
    uname        => 'TEST_USER',
    orig_table   => 'TEST_TABLE',
    int_table    => 'TEST_TABLE_INT',
    col_mapping  => 'id id, name name, created_date created_date, value value, new_column new_column',
    options_flag => DBMS_REDEFINITION.CONS_USE_PK
  );
END;
/
复制代码
# 复制依赖对象(自动复制索引、触发器等)
DECLARE
  num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
    uname          => 'TEST_USER',
    orig_table     => 'TEST_TABLE',
    int_table      => 'TEST_TABLE_INT',
    copy_indexes   => DBMS_REDEFINITION.CONS_ORIG_PARAMS,
    copy_triggers  => TRUE,
    ignore_errors  => TRUE,
    num_errors     => num_errors
  );
  DBMS_OUTPUT.PUT_LINE('依赖对象错误: ' || num_errors);
END;
/
复制代码
# 同步数据
BEGIN
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
    uname        => 'TEST_USER',
    orig_table   => 'TEST_TABLE',
    int_table    => 'TEST_TABLE_INT'
  );
END;
/
复制代码
# 完成重定义(短暂锁表)
BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE(
    uname        => 'TEST_USER',
    orig_table   => 'TEST_TABLE',
    int_table    => 'TEST_TABLE_INT'
  );
END;
/

高水位线回收(碎片整理)

复制代码
# 记录当前高水位线
SELECT blocks, empty_blocks 
FROM dba_tables 
WHERE owner = 'TEST_USER' AND table_name = 'TEST_TABLE';
复制代码
#检查选择的表是否可以执行在线重定义
BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE('TEST_USER', 'TEST_TABLE');
END;
/
复制代码
#创建中间表
CREATE TABLE test_user.test_table_int (
    id NUMBER PRIMARY KEY,
    name VARCHAR2(100) NOT NULL,
    created_date DATE,
    value NUMBER(10),
    new_column VARCHAR2(50)
) TABLESPACE test_tbs;
复制代码
# 开始在线重定义(使用主键方式)
BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE(
    uname        => 'TEST_USER',
    orig_table   => 'TEST_TABLE',
    int_table    => 'TEST_TABLE_INT',
    col_mapping  => 'id id, 
                     name name, 
                     created_date created_date, 
                     value value, 
                     new_column new_column',  
    options_flag => DBMS_REDEFINITION.CONS_USE_PK
  );
END;
/
复制代码
-- 复制依赖对象(自动复制索引、约束)
DECLARE
  num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT',
    copy_indexes => DBMS_REDEFINITION.CONS_ORIG_PARAMS,
    copy_triggers => TRUE,
    copy_constraints => TRUE,
    copy_privileges => TRUE,
    ignore_errors => TRUE,
    num_errors => num_errors
  );
END;
/
复制代码
# 同步数据
BEGIN
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT'
  );
END;
/
复制代码
# 完成重定义

# DBMS_REDEFINITION.FINISH_REDEF_TABLE 会执行flush shard pool 需要规避
alter session set events '10995 trace name context forever, level 2';

BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE(
    uname => 'TEST_USER',
    orig_table => 'TEST_TABLE',
    int_table => 'TEST_TABLE_INT'
  );
END;
/

检查高水位是否回收

复制代码
SELECT blocks, empty_blocks 
FROM dba_tables 
WHERE owner = 'TEST_USER' AND table_name = 'TEST_TABLE';

转换为索引组织表(IOT)

总体步骤都与前面相同

相关推荐
电商API_180079052477 小时前
第三方淘宝商品详情 API 全维度调用指南:从技术对接到生产落地
java·大数据·前端·数据库·人工智能·网络爬虫
晓晓莺歌7 小时前
vue3某一个路由切换,导致所有路由页面均变成空白页
前端·vue.js
Genie cloud7 小时前
1Panel SSL证书申请完整教程
服务器·网络协议·云计算·ssl
一点程序7 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
C雨后彩虹7 小时前
计算疫情扩散时间
java·数据结构·算法·华为·面试
2601_949809597 小时前
flutter_for_openharmony家庭相册app实战+我的Tab实现
java·javascript·flutter
Up九五小庞7 小时前
开源埋点分析平台 ClkLog 本地部署 + Web JS 埋点测试实战--九五小庞
前端·javascript·开源
!chen8 小时前
linux服务器静默安装Oracle26ai
linux·运维·服务器
莫大3308 小时前
2核2G云服务器PHP8.5+MySQL9.0+Nginx(LNMP)安装WordPress网站详细教程
运维·服务器·nginx
vx_BS813308 小时前
【直接可用源码免费送】计算机毕业设计精选项目03574基于Python的网上商城管理系统设计与实现:Java/PHP/Python/C#小程序、单片机、成品+文档源码支持定制
java·python·课程设计