前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于 dbms_redefinition 在线重定义表

基于 dbms_redefinition 在线重定义表

作者头像
Leshami
发布2018-08-13 15:25:57
9160
发布2018-08-13 15:25:57
举报
文章被收录于专栏:乐沙弥的世界乐沙弥的世界

      Oracle 支持在线重定义表,也就是说我们可以在修改表结构(DDL)的同时进行相关的DQL、DML操作,使得前端的DML根本感觉不到表结构实际上已经发生了变化,对于用户而言是完全透明的。当然在线重定义期间,前端性能会稍微有所下降。Oracle提供的重定义包dbms_redefinition即是用与完成此操作。其实质是Oracle使用了智能物化视图及物化视图日志的方式。在对象结构重组期间,表现为一个本地对象的复制,重组期间发生的任何变化都会被刷新到最新。

1、在线重定义表的主要功能:      修改表或簇的存储参数      将表移动到相同或不同schema下不同的tablespace(如果不要求表始终可用的话,也可以直接使用alter table move 实现)      为表添加,修改或删除列      为表添加或删除分区,改变分区结构      改变物化视图日志或者Streams Advanced Queuing queue 表结构      增加并行查询支持      重建表以减少碎片      将堆表变为索引组织表或相反

2、图示在线重定义      下面的图示便于理解是如何进行在线重定义,其本质是基于基表的一个快照

3、在线重定义的步骤       a、选择在线重定义的方式,基于键(主键或唯一键)还是rowid(无主键或唯一键的情形)      b、校验表能否被在线重定义,使用过程CAN_REDEF_TABLE      c、创建用于在线重定义的临时表(该临时表使用新的表结构,即添加删除列,列长度变化,存储属性变化等)      d、如果重定义的为分区表且使用rowid方式,应该为临时表开启行移动(ALTER TABLE ... ENABLE ROW MOVEMENT;)      e、对于大型表的在线重定义可以通过启用并行以提高性能(此步骤可选)           ALTER SESSION FORCE PARALLEL DML PARALLEL degree-of-parallelism;           ALTER SESSION FORCE PARALLEL QUERY PARALLEL degree-of-parallelism;      f、调用过程start_redef_table启动在线重定义,如果启动失败,应调用ABORT_REDEF_TABLE先终止查找原因后再次启动      g、从被重定义的表复制依赖对象到临时表(triggers, indexes, materialized view logs, grants, and constraints)及统计信息到临时表      h、同步被重定义的表到临时表(调用过程sync_interim_table,此步可选)      i、调用过程FINISH_REDEF_TABLE完成表的在线重订义      j、删除临时表

4、演示在线重定义

代码语言:javascript
复制
--下面基于主键来演示在线重定义
--环境
scott@USBO> select * from v$version where rownum<2;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

--创建需要重定义的表
scott@USBO> create table tb_emp(empno number(4) not null,ename varchar2(10),
  2  job varchar2(10),hiredate varchar2(20),sal number(7,2),deptno number(2));

--下面为其添加相关约束
scott@USBO> alter table tb_emp add constraint pk_tb_emp primary key(empno);

scott@USBO> alter table tb_emp add constraint fk_tb_emp_dept_no foreign key(deptno) references dept(deptno);

--创建用于在线重定义的临时表
--注意,empno列可以为NULL,ename变化为name且长度增加,sal变为salary,数据精度发生变化,以及deptno使用了default
scott@USBO> create table tb_emp_int
  2  (empno number(4),name varchar2(20),hiredate varchar2(20),salary number,deptno number(2) default 30);

--基于重定义创建触发器
scott@USBO> CREATE OR REPLACE TRIGGER tr_bf_tb_emp_hiredate
  2     BEFORE UPDATE OF hiredate
  3     ON tb_emp
  4     FOR EACH ROW
  5  BEGIN
  6     :new.hiredate := TO_CHAR (SYSDATE, 'yyyymmdd hh24:mi:ss');
  7  END tr_bf_tb_emp_hiredate;
  8  /

Trigger created.

--基于中间表创建触发器
scott@USBO> CREATE OR REPLACE TRIGGER tr_bf_tb_emp_int_hiredate
  2     BEFORE UPDATE OF hiredate
  3     ON tb_emp_int
  4     FOR EACH ROW
  5  BEGIN
  6     :new.hiredate := TO_CHAR (SYSDATE + 10, 'yyyymmdd hh24:mi:ss');
  7  END tr_bf_tb_emp_int_hiredate;
  8  /

Trigger created.

--收集统计信息
scott@USBO> exec dbms_stats.gather_table_stats('SCOTT','TB_EMP',cascade=>true);

scott@USBO> exec dbms_stats.gather_table_stats('SCOTT','TB_EMP_INT',cascade=>true);

scott@USBO> select table_name,num_rows from user_tables where table_name like 'TB_EMP%';

TABLE_NAME                       NUM_ROWS
------------------------------ ----------
TB_EMP                                  0
TB_EMP_INT                              0

--对重定义表执行DML操作
--此时使用了dbms_lock.sleep (5),也就是整个操作完成需要500s,我们在这个期间实施重定义
scott@USBO> get ins_tb_emp.sql
  1  DECLARE
  2     v_deptno   NUMBER (2);
  3  BEGIN
  4     FOR i IN 1 .. 100
  5     LOOP
  6        IF MOD (i, 2) = 0
  7        THEN
  8           v_deptno := 10;
  9        ELSE
 10           v_deptno := 20;
 11        END IF;
 12        INSERT INTO tb_emp
 13           SELECT i,
 14                  'Name_' || TO_CHAR (i),
 15                  'Job_' || TO_CHAR (i),
 16                  TO_CHAR (SYSDATE, 'yyyymmdd hh24:mi:ss'),
 17                  i + 100,
 18                  v_deptno
 19             FROM DUAL;
 20        dbms_lock.sleep (5);
 21        COMMIT;
 22     END LOOP;
 23* END;
 24  /
 
--下面再开启一个新的session,用于在线重定义表 
scott@USBO> set serveroutput on;
--校验表能否被重定义
scott@USBO> exec dbms_redefinition.can_redef_table('SCOTT','TB_EMP');

--开始重定义
scott@USBO> exec dbms_redefinition.start_redef_table('SCOTT', 'TB_EMP', 'TB_EMP_INT',-
> 'EMPNO EMPNO, ENAME NAME, SAL*1.10 SALARY, HIREDATE HIREDATE,DEPTNO DEPTNO');

--可以从视图user_snapshots查询到临时表的信息
scott@USBO> select name,table_name,updatable,status from user_snapshots;

NAME                           TABLE_NAME                     UPD STATUS
------------------------------ ------------------------------ --- -------
TB_EMP_INT                     TB_EMP_INT                     NO  VALID

--查看表tb_emp_int,此时也有5条记录被插入
scott@USBO> select count(*) from tb_emp_int;

  COUNT(*)
----------
         5

--正在插入到tb_emp_int产生的日志信息,从6开始,实际上执行start_redef_table时前5条记录已经被复制到临时表        
scott@USBO> select * from mlog$_tb_emp;

     EMPNO SNAPTIME$$        D O CHANGE_VEC      XID$$
---------- ----------------- - - ---------- ----------
         6 40000101 00:00:00 I N FE         1.4074E+15
         7 40000101 00:00:00 I N FE         5.6299E+14
         8 40000101 00:00:00 I N FE         2.2519E+15
         9 40000101 00:00:00 I N FE         1.4075E+15

scott@USBO> select * from rupd$_tb_emp;

no rows selected

--检查约束等是否已经添加到临时表
scott@USBO> select constraint_name,table_name,status from user_constraints where table_name='TB_EMP_INT';

no rows selected

--注册依赖对象        
scott@USBO> exec dbms_redefinition.register_dependent_object('SCOTT', 'TB_EMP', 'TB_EMP_INT', -
> dbms_redefinition.cons_trigger, 'SCOTT', 'tr_bf_tb_emp_hiredate', 'tr_bf_tb_emp_int_hiredate');

PL/SQL procedure successfully completed.

scott@USBO> select constraint_name,table_name,status from user_constraints where table_name='TB_EMP_INT';

no rows selected

--将重定义表的依赖对象复制到临时表
scott@USBO> DECLARE       
  2     retval   NUMBER (5);
  3  BEGIN
  4     DBMS_REDEFINITION.copy_table_dependents ('SCOTT', 'TB_EMP', 'TB_EMP_INT', 0,
  5                                              copy_constraints   => TRUE,
  6                                              num_errors         => retval);
  7     DBMS_OUTPUT.put_line (retval);
  8  END;
  9  /

PL/SQL procedure successfully completed.

--查看临时表上的依赖对象,可以看到出现了以TMP$$开头的相关约束
scott@USBO> select constraint_name,table_name,status from user_constraints where table_name in('TB_EMP_INT','TB_EMP');

CONSTRAINT_NAME                TABLE_NAME                     STATUS
------------------------------ ------------------------------ --------
SYS_C0024681                   TB_EMP                         ENABLED
PK_TB_EMP                      TB_EMP                         ENABLED
FK_TB_EMP_DEPT_NO              TB_EMP                         ENABLED
TMP$$_SYS_C00246810            TB_EMP_INT                     ENABLED
TMP$$_PK_TB_EMP0               TB_EMP_INT                     ENABLED
TMP$$_FK_TB_EMP_DEPT_NO0       TB_EMP_INT                     DISABLED

--查看表tb_emp,此时重定义表插入了36条记录
scott@USBO> select count(*) from tb_emp;

  COUNT(*)
----------
        36

--临时表上的记录为5        
scott@USBO> select count(*) from tb_emp_int;

  COUNT(*)
----------
         5                       

--下面的过程用于同步重定义表与临时表
scott@USBO> exec dbms_redefinition.sync_interim_table('SCOTT', 'TB_EMP', 'TB_EMP_INT');

PL/SQL procedure successfully completed.           

--这是同步后的结果
scott@USBO> select count(*) from tb_emp_int;

  COUNT(*)
----------
        39

--最后完成在线重定义,此时如果重定义表上事务没有被完成,需要等到所有事务完成
scott@USBO> exec dbms_redefinition.finish_redef_table('SCOTT', 'TB_EMP', 'TB_EMP_INT');

PL/SQL procedure successfully completed.

scott@USBO> select count(*) from tb_emp_int;

  COUNT(*)
----------
       100       

--检验结果,可以看到列salary上的值发生了变化      
scott@USBO> select new.salary new_sal, old.sal old_sal,new.deptno new_deptno,old.deptno old_detpno
  2  from tb_emp new, tb_emp_int old
  3  where new.empno = old.empno and rownum<=3;

   NEW_SAL    OLD_SAL NEW_DEPTNO OLD_DETPNO
---------- ---------- ---------- ----------
     111.1        101         20         20
     112.2        102         10         10
     113.3        103         20         20

--验证触发器
scott@USBO> select table_name, trigger_name
  2  from user_triggers;

TABLE_NAME                     TRIGGER_NAME
------------------------------ ------------------------------
TB_EMP                         TR_BF_TB_EMP_HIREDATE
TB_EMP_INT                     TR_BF_TB_EMP_INT_HIREDATE

--Author : Leshami
--Blog   : http://blog.csdn.net/leshami

--此时临时表上的触发器被应用到重定义的表
scott@USBO> select trigger_body from user_triggers
  2  where table_name = 'TB_EMP';

TRIGGER_BODY
--------------------------------------------------------------------------------
BEGIN
   :new.hiredate := to_char(SYSDATE + 10,'yyyymmdd hh24:mi:ss');
END tr_bf_int_emp_hiredate;

scott@USBO> desc tb_emp
 Name                                                                                Null?    Type
 ----------------------------------------------------------------------------------- -------- --------------------
 EMPNO                                                                                        NUMBER(4)
 NAME                                                                                         VARCHAR2(20)
 HIREDATE                                                                                     VARCHAR2(20)
 SALARY                                                                                       NUMBER
 DEPTNO                                                                                       NUMBER(2)
 
 scott@USBO> select column_name,data_type, data_default from dba_tab_columns
  2  where owner='SCOTT' and table_name='TB_EMP' and column_name='DEPTNO';

Column Name          Data Type                 DATA_DEFAULT
-------------------- ------------------------- ------------------------------------------------------------------
DEPTNO               NUMBER                    30
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2013年09月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档