在高可用环境中,我们会使用在线重定义表来重新整理表,
其内部原理根据MV来实现的,类似现在原表上创建一个MV,然后一直增量刷新到数据差别最小,
完全同步->增量同步->切换完成。
可以完成:
修改表的一些参数,一些需要重组才能起效的特性,比如initrans
重组表数据,压缩空间
在线把表从一个表空间迁移到另外一个表空间
吧表从分区表转为普通表,或者普通表转为分区表
在线删除字段
二、实例
1) 创建实验用户
SQL> create user test identified bytest;
User created
SQL> grant connect,resource to test;
Grant succeeded
SQL> conn test/test
SQL> conn test/test@orcl_76
Connected to Oracle Database 11g EnterpriseEdition Release 11.2.0.1.0
Connected as test@orcl_76
2) 创建测试表,
SQL>create table t(a int,b int);
Tablecreated
declare iint;
begin
for i in1..100 loop
insertinto t values(i,100-i);
end loop;
commit;
end;
SQL>create table t1 (c int);
Tablecreated
SQL>
SQL>create trigger tr_t
2 before insert or update or delete on t
3 for each row
4 declare
5 PRAGMA AUTONOMOUS_TRANSACTION;--- 般情况下利用触发器禁止某些对表的更新等操作时,若记录日志,则触发器最后抛出异常时会造成日志回滚。利用自治事务可防止此点,结束时需要明确commit、ROLLBACK或执行DDL
6 begin
7 update t1 set c=c+1;
8 commit;
9 end;
10 /
SQL>insert into c values(0);
insert into c values(0)
commit
SQL>insert into t values(0,0);
1 rowinserted
SQL>select * from t1;
C
---------------------------------------
1
3) 检查可行性
给用户test 赋予dba权限
然后
SQL>exec dbms_redefinition.can_redef_table('TEST','T');
begindbms_redefinition.can_redef_table('TEST','T'); end;
ORA-12089:不能联机重新定义无主键的表 "TEST"."T"
ORA-06512:在 "SYS.DBMS_REDEFINITION", line 139
ORA-06512:在 "SYS.DBMS_REDEFINITION", line 1782
ORA-06512:在 line 2
SQL>exec dbms_redefinition.can_redef_table('TEST','T');
PL/SQLprocedure successfully completed
SQL>alter table t add constraint pk_t_id primary key(a);
Table altered
4) 创建中间表
create table t_temp (a int,b int,c int)
partition by range(a)
(partition p10 values less than(50),
partition p20 values less than (100),
partition p30 values less than (200));
5) 执行在线重定义
SQL> executedbms_redefinition.start_redef_table('TEST','T','T_TEMP','a a,b b,0 c');
PL/SQL procedure successfully completed
101
SQL> selectobject_name,object_type,status,object_id,data_object_id from user_objects orderby 4;
OBJECT_NAME OBJECT_TYPE STATUS OBJECT_ID DATA_OBJECT_ID
--------------------------------------------------------------------------------------------------- ------- ---------- --------------
T TABLE VALID 77512 77512
TR_T TRIGGER VALID 77513
T1 TABLE VALID 77514 77514
PK_T_ID INDEX VALID 77515 77515
T_TEMP TABLE VALID 77516
T_TEMP TABLE PARTITION VALID 77517 77517
T_TEMP TABLE PARTITION VALID 77518 77518
T_TEMP TABLE PARTITION VALID 77519 77519
MLOG$_T TABLE VALID 77520 77520
RUPD$_T TABLE VALID 77521
查询,看到这些中间表示mv,并且一个婊mlog$_t表示一个t的快照日志,记录t正式切换前的改变日志,原理跟mv差不多,另外一个是临时表rupd$_t,这个在mv刷新时用到
SQL> selectmview_name,container_name,build_mode from user_mviesw;
select mview_name,container_name,build_modefrom user_mviesw
ORA-00942: 表或视图不存在
SQL> selectmview_name,container_name,build_mode from user_mviews;
MVIEW_NAME CONTAINER_NAME BUILD_MODE
------------------------------------------------------------ ----------
T_TEMP T_TEMP PREBUILT
6) 在新创建的表上创建主键或者非空唯一约束
SQL> alter
2 table t_temp add constraint t_temp_pk primary key(a);
Tablealtered
创建trigger
SQL> create trigger tr_t_temp
2 before insert or update ordelete on t
3 for each row
4 declare
5 PRAGMAAUTONOMOUS_TRANSACTION;
6 begin
7 update t1 set c=c+1;
8 commit;
9 end;
10 /
SQL> select trigger_name,status from user_triggers;
TRIGGER_NAME STATUS
------------------------------ --------
TR_T ENABLED
TR_T_TEMP ENABLED
这个时候插入原表一行---查看表t1,但是没有增加
SQL> insert into t values(102,1);
1 row inserted
SQL> select count(*) from t;
COUNT(*)
----------
102
SQL> select count(*) from t_temp;
COUNT(*)
----------
101
SQL> select count(*) from mlog$_t;
COUNT(*)
----------
1
SQL> select count(*) from rupd$_t;
COUNT(*)
----------
0
SQL> select c from t1;
C
---------------------------------------
4
可以看到日志增加了一行
7) 执行表的同步
SQL> insert into t values(103,1);
1 row inserted
SQL> commit;
Commit complete
SQL> select count(*) from t;
COUNT(*)
----------
102
SQL> select count(*) from t_temp;
COUNT(*)
----------
101
SQL> select count(*) from mlog$_t;
COUNT(*)
----------
1
SQL> executedbms_redefinition.sync_interim_table('TEST','T','T_TEMP');
PL/SQL procedure successfully completed
SQL> select count(*) from mlog$_t;
COUNT(*)
----------
0
SQL> select count(*) from t_temp;
COUNT(*)
----------
102
SQL> select count(*) from t;
COUNT(*)
----------
102
8) 执行重构完成的过程
executedbms_redefinition.finish_redef_table('TEST','T','T_TEMP');
这个过程不要操之过急,因为我在弄得时候,太急了,执行了两次,第一个没搞完,所以死了,然后我就abort了
取消用dbms_redefinition.abort_redef_table(‘TEST’,’T’,’T_TEMP’)
执行完了需要删除表t_temp,这样就执行完了全部过程
三、可用性要求不高的重定义
在可用性不高的环境中一般我们可以使用move实现重定义
表:
Alter table table_name move tablespacetbs_name
表重定义之后索引等全部失效,需要重建
索引可以在线重建
Alter index index_name rebuild tablespace tbs_name [online]
还有合并索引
Alter Alter index index_name coalesce ---碎片化整理
索引倾斜导致索引空间增加时,小值一端的空间很难被重用,这样应该定期重建索引
以下是建议:
如果表的块已经非常热,空间合并之后,新的快可能更热,导致buffer busy的等待或者热点快问题
如果索引不是由于倾斜引起的膨胀,如果很稳定就不建议rebuild,