2354 字
12 分钟
在线重定义分区表

在线重定义为分区表 参考: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/vldbg/evolve-nopartition-table.html#GUID-6054142E-207A-4DF0-A62A-4C1A94DD36C4 https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/DBMS_REDEFINITION.html#GUID-09FE5412-519C-412F-B1E0-77F75B1E8CA7

一、 DBMS_REDEFINITION.START_REDEF_TABLE 是 Oracle 数据库中的一个过程,用于启动表的在线重定义(Online Table Redefinition)过程。在线重定义是一种技术, 允许你在不中断正常数据库操作的情况下修改表的结构(例如添加、删除列,修改数据类型等)。

使用 DBMS_REDEFINITION.START_REDEF_TABLE 过程,可以在不停机的情况下进行以下操作: 表结构的修改: 可以添加、删除、修改表的列,修改数据类型等。 表的分区和分区键的修改: 可以对分区表的分区键进行修改。 索引的修改: 可以添加、删除、修改索引。 触发器、约束等的修改: 可以添加、删除、修改触发器、约束等。

在线重定义的过程可以分为以下几个步骤:

初始化: 创建一个用于在线重定义的临时表,将原始表的数据复制到临时表中。 同步: 在在线重定义过程中,继续收集在原始表上的DML(Data Manipulation Language)操作,以确保数据的一致性。 完成: 当所有的DML操作都同步到了临时表后,将DML操作应用到临时表,并将临时表的数据同步回原始表。

使用 DBMS_REDEFINITION.START_REDEF_TABLE 过程,可以启动在线重定义的过程,然后使用其他相关的 DBMS_REDEFINITION 过程来完成重定义过程。

二、 DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS 是 Oracle 数据库中的一个过程,用于在执行在线表重定义(Online Table Redefinition)过程时, 将源表的相关依赖对象(例如索引、触发器、外键等)复制到重新定义后的目标表上。

在进行在线表重定义时,不仅需要考虑源表的数据迁移,还需要处理与表相关的依赖对象。COPY_TABLE_DEPENDENTS 过程的作用就是帮助你处理这些依赖对象, 确保它们在表重定义完成后的新表上存在并且是有效的。

使用 DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS 过程,你可以在在线表重定义过程中执行以下操作: 复制索引: 将源表上的索引复制到新表上。 复制触发器: 将源表上的触发器复制到新表上。 复制外键: 将源表上的外键关系复制到新表上。 复制其他依赖对象: 复制其他与表相关的依赖对象,例如检查约束等。

三、 DBMS_REDEFINITION.FINISH_REDEF_TABLE 过程用于完成在线表重定义的最后一步,即将临时表的数据同步回原始表,然后清理和完成在线重定义过程。

################################################环境准备################################################ 1.使用sysdba权限登陆数据库 CONNECT / AS SYSDBA

2.创建eqnt测试用户,并授权 DROP USER eqnt CASCADE; CREATE USER eqnt IDENTIFIED BY eqnt; GRANT CONNECT, RESOURCE TO eqnt;

— Grant privleges required for online redefinition. GRANT EXECUTE ON DBMS_REDEFINITION TO eqnt; GRANT ALTER ANY TABLE TO eqnt; GRANT DROP ANY TABLE TO eqnt; GRANT LOCK ANY TABLE TO eqnt; GRANT CREATE ANY TABLE TO eqnt; GRANT SELECT ANY TABLE TO eqnt;

— Privileges required to perform cloning of dependent objects. GRANT CREATE ANY TRIGGER TO eqnt; GRANT CREATE ANY INDEX TO eqnt;

—表空间授权 ALTER USER eqnt QUOTA UNLIMITED ON “USERS”;

3.切换到eqnt连接,创建测试数据 CONNECT eqnt/eqnt

— (old) non partitioned nested table CREATE TABLE print_media ( product_id NUMBER(6), ad_textdocs_ntab VARCHAR2(22) );

INSERT INTO print_media VALUES (1,‘xx’); INSERT INTO print_media VALUES (11,‘aa’); COMMIT;

—建主键索引 CREATE UNIQUE INDEX pk_print_media ON print_media(product_id) PARALLEL 4 INITRANS 16; alter table print_media add constraint pk_print_media primary key (product_id) using INDEX;

—检查user_objects对象 SELECT * FROM user_objects

—共两个对象 PK_PRINT_MEDIA INDEX —PRINT_MEDIA表的索引 PRINT_MEDIA TABLE —第一次建的表

— Creating partitioned Interim Table CREATE TABLE print_media2 ( product_id NUMBER(6) , ad_textdocs_ntab VARCHAR2(22) ) PARTITION BY RANGE (product_id) ( PARTITION P1 VALUES LESS THAN (10), PARTITION P2 VALUES LESS THAN (20) );

—检查user_objects对象 SELECT * FROM user_objects

PK_PRINT_MEDIA INDEX —PRINT_MEDIA表的索引 PRINT_MEDIA2 P2 TABLE PARTITION —PRINT_MEDIA2的分区 PRINT_MEDIA2 P1 TABLE PARTITION —PRINT_MEDIA2的分区 PRINT_MEDIA2 TABLE —第二次建的表 PRINT_MEDIA TABLE —第一次建的表

################################################在线重定义################################################

1.开始在线表重定义

BEGIN DBMS_REDEFINITION.START_REDEF_TABLE( uname => ‘eqnt’, —源表所属的用户(schema)名称 orig_table => ‘print_media’, —原始表的名称 int_table => ‘print_media2’ —,中间表(interim table)的名称,即在线重定义过程中使用的临时表 —col_mapping => ,—字段映射规则,用于将源表的列映射到中间表的列,表结构相同时不需要指定 —规则格式为 source_column,source_column,… 我的理解为修改表中字段位置使用

—options_flag => ,—控制在线表重定义的选项。常用的取值是 DBMS_REDEFINITION.CONS_USE_ROWID, —表示使用ROWID进行映射…理解为 options_flag => DBMS_REDEFINITION.CONS_USE_ROWID

—orderby_cols => ,—用于指定在从源表复制数据到中间表时的排序规则,column1 ASC, column2 DESC,默认值为 NULL —p****** => ,—用于指定分区表中的特定分区,如果原始表是分区表理解为只针对某一个分区进行重定义 part_name,默认值为 NULL —continue_after_errors => ,—指定是否在遇到错误时继续执行,TRUE 表示继续执行,FALSE 表示遇到错误就停止,默认值为 TRUE —copy_vpd_opt => ,—是否复制源表上的 Virtual Private Database (VPD) 选项,TRUE 表示复制,FALSE 表示不复制,默认值为 TRUE —refresh_dep_mviews => ,—是否刷新依赖于源表的物化视图,TRUE 表示刷新,FALSE 表示不刷新,默认值为 TRUE —enable_rollback => —是否启用回滚,TRUE 表示启用,FALSE 表示不启用,默认值为 TRUE ); END;

—检查user_objects对象 SELECT * FROM user_objects

PK_PRINT_MEDIA INDEX —PRINT_MEDIA表的索引 PRINT_MEDIA2 P2 TABLE PARTITION —PRINT_MEDIA2的分区 PRINT_MEDIA2 P1 TABLE PARTITION —PRINT_MEDIA2的分区 PRINT_MEDIA2 TABLE —第二次建的表 MLOGPRINTMEDIATABLE多出来的表aPRINTMEDIATABLE第一次建的表RUPD_PRINT_MEDIA TABLE --多出来的表a PRINT_MEDIA TABLE --第一次建的表 RUPD_PRINT_MEDIA TABLE —多出来的表b I_MLOG$_PRINT_MEDIA INDEX —多出来的索引

2.查看四张表变化过程 SELECT T1.*,ROWID FROM PRINT_MEDIA T1;

SELECT T2.*,ROWID FROM PRINT_MEDIA2 T2;

SELECT T3.*,ROWID FROM MLOG$_PRINT_MEDIA T3;

SELECT T4.*,ROWID FROM RUPD$_PRINT_MEDIA T4;

其中 PRINT_MEDIA 表没有变化 其中 PRINT_MEDIA2 表同步了PRINT_MEDIA的数据 其中 MLOGPRINTMEDIA无值其中RUPD_PRINT_MEDIA 无值 其中 RUPD_PRINT_MEDIA 无值

PRINT_MEDIA ROWID AAATL7AAMAAAACtAAA AAATL7AAMAAAACtAAB

PRINT_MEDIA2 ROWID AAATL+AAMAAAA4SAAA AAATL/AAMAAABISAAA

使用plsql查看表的建立,发现已经变成了物化视图 /* CREATE MATERIALIZED VIEW PRINT_MEDIA2 ON PREBUILT TABLE REFRESH FAST ON DEMAND AS SELECT “PRINT_MEDIA”.”PRODUCT_ID” “PRODUCT_ID”,“PRINT_MEDIA”.”AD_TEXTDOCS_NTAB” “AD_TEXTDOCS_NTAB” FROM “EQNT”.”PRINT_MEDIA” “PRINT_MEDIA”; */

尝试删除 print_media2 表 DROP TABLE print_media2 PURGE; 报错: ORA-12083:必须使用 DROP MATERIALIZED VIEW 来删除“EQNT”.”PRINT MEDIA2

这里删表必须删除物化视图才能做删表操作 例: DROP MATERIALIZED VIEW print_media2 ; DROP TABLE print_media2 PURGE;

3.对源表插入数据

INSERT INTO print_media VALUES (3,‘cc’); UPDATE print_media t SET t.product_id=2 WHERE t.product_id=11; DELETE FROM print_media t WHERE t.product_id=1; COMMIT;

4.查看四张表变化过程 SELECT T1.*,ROWID FROM PRINT_MEDIA T1;

SELECT T2.*,ROWID FROM PRINT_MEDIA2 T2;

SELECT T3.*,ROWID FROM MLOG$_PRINT_MEDIA T3;

SELECT T4.*,ROWID FROM RUPD$_PRINT_MEDIA T4;

其中 PRINT_MEDIA 表同修改语句变化 其中 PRINT_MEDIA2 表没有变化 其中 MLOGPRINTMEDIA记录了三次其中RUPD_PRINT_MEDIA 记录了三次 其中 RUPD_PRINT_MEDIA 无值

PRINT_MEDIA ROWID AAATL7AAMAAAACtAAB AAATL7AAMAAAACtAAC

PRINT_MEDIA2 ROWID AAATL+AAMAAAA4SAAA AAATL/AAMAAABISAAA

MLOG$_PRINT_MEDIA 表记录内容(全是PRINT_MEDIA的变化) 3 I N FE 1.12595574141939E15 AAATMAAAMAAAA1dAAA —insert引起 11 D O 00 2.81486143626754E15 AAATMAAAMAAAA1dAAB —update引起,先删除 2 I N FF 2.81486143626754E15 AAATMAAAMAAAA1dAAC —update引起,再插入 1 D O 00 2.81487432116942E15 AAATMAAAMAAAA1dAAD —delete引起

5.复制依赖对象,包括主键约束 —所有的参数都没有默认值。每个参数都需要明确提供值,否则过程无法执行。

DECLARE error_count pls_integer := 0; BEGIN dbms_redefinition.copy_table_dependents( uname => ‘eqnt’,—源表所属的用户(schema)名称 orig_table => ‘print_media’,—原始表的名称 int_table => ‘print_media2’,—中间表(interim table)的名称,即在线重定义过程中使用的临时表 copy_indexes => 1,—是否复制源表上的索引,1 表示复制索引,0 表示不复制索引 copy_triggers => TRUE,—是否复制源表上的触发器,TRUE 表示复制触发器,FALSE 表示不复制触发器 copy_constraints => TRUE,—是否复制源表上的约束。可以使用常量,DBMS_REDEFINITION.CONS_ORIG_PARAMS’ 表示复制约束 copy_privileges => TRUE,—是否复制源表上的权限信息,TRUE 表示复制权限,FALSE 表示不复制权限 ignore_errors => FALSE,—指定是否忽略在复制依赖对象过程中发生的错误,TRUE 表示忽略错误,FALSE 表示不忽略错误 num_errors => error_count,—用于返回在复制依赖对象过程中发生的错误数量 copy_statistics => TRUE,—是否复制源表上的统计信息,TRUE 表示复制统计信息,FALSE 表示不复制统计信息 copy_mvlog => FALSE —是否复制源表上的物化视图日志,TRUE 表示复制物化视图日志,FALSE 表示不复制物化视图日志 );

dbms_output.put_line(‘errors := ’ || to_char(error_count)); END;

检查数据结果为 errors := 0

—检查user_objects对象 SELECT * FROM user_objects

检查结果: 多了一个索引 TMP$$_PK_PRINT_MEDIA0

6.结束在线表重定义

BEGIN dbms_redefinition.finish_redef_table( uname => ‘eqnt’,—源表所属的用户(schema)名称 orig_table => ‘print_media’,—原始表的名称 int_table => ‘print_media2’—,中间表(interim table)的名称,即在线重定义过程中使用的临时表 —p****** => ,—用于指定分区表中的特定分区,如果原始表是分区表 —dml_lock_timeout => ,— DML 操作的锁定超时时间,单位是秒。如果不指定,默认值是 NULL —continue_after_errors => ,—指定是否在遇到错误时继续执行,TRUE 表示继续执行,FALSE 表示遇到错误就停止 —disable_rollback => —是否禁用回滚操作,TRUE 表示禁用回滚,FALSE 表示允许回滚 ); END;

—检查user_objects对象 SELECT * FROM user_objects

以下表和索引消失 MLOGPRINTMEDIATABLE多出来的表aRUPD_PRINT_MEDIA TABLE --多出来的表a RUPD_PRINT_MEDIA TABLE —多出来的表b I_MLOG$_PRINT_MEDIA INDEX —多出来的索引

7.验证新表 SELECT * FROM print_media

— Drop the interim table DROP TABLE print_media2; 成功删除

—清回收站 PURGE RECYCLEBIN;

—检查user_objects对象 SELECT * FROM user_objects

名字及索引名已成功修改

在线重定义分区表
https://blog.newworld.help/posts/在线重定义分区表/
作者
勇敢DBA不怕困难
发布于
2025-12-12
许可协议
CC BY-NC-SA 4.0