活动预告

在线重定义的补充测试

杨建荣 2016-10-12 09:42:32
 在很多时候,我们都是需要保持业务的可持续性,尽管说DDL的过程持续时间很短,但是在线业务出现,就会阻塞DML,导致业务访问中断,事务收到影响,所以在有些场景下,高可用的需求可能比性能的需求优先级还要高一些。
    比如一个分区表,突然发现分区的规则存在一些问题,如果需要重新规划分区,部署,可能对于在线业务影响较大,能不能平滑的过渡到重新规划的分区模式下。
    比如一个普通表,随着数据量的增加发现已经存在一些管理瓶颈,比如历史数据的清理比较麻烦,想改为分区表的方式
    比如一个表需要添加若干字段,数据类型也需要调整等等,这类变更如果通过DDL完成对于在线业务的影响范围较大
    比如一个表所在的分区空间不足,希望能够在业务低峰期进行数据的重构。
有了在线重定义,这些看似困难的工作就会存在可能性,当然万事皆须付出代价,那就是在线重定义本身会消耗系统资源,这个需要合理评估,找到一个合适的时间点来完成。毕竟为了完成高可用的需求而带来了严重的性能问题,那就得不偿失了。
    有些场景还是不大适合在线重定义的,比如一个数据库的表大小为50G,空间剩余不足10G,我们如果使用在线重定义的方案,那么就会存在很大的隐患。因为在线重定义本质上还是需要做一次底层的数据复制。这个就需要消耗系统资源,磁盘空间。
    在线重定义的一个亮点就是保持数据的可持续访问,基本原理是通过物化视图的prebuilt方式完成,所以这种方案本身就是高可用,物化视图的过程中对外是始终保持可访问的连续性状态,那么对于权限的控制则是这个之外的,所以我格外关心这部分的内容。如果我们的环境存在下面这样的情况,到底在线重定义的过程中是否会很稳定呢,我们可以做对比测试来验证。
如果存在大量的连接用户,在线重定义是否依然能够保证业务的可持续进行。

尽管我们知道从技术原理上是可以支持的,但是如果进一步验证测试,我想就需要更全面的测试环境了。
我们分为三个场景来测试。
第一个是通过shell不断生成会话去使用SQL调用基表的数据,看看是否会有中断。
第二个是通过一个已经存在的会话窗口不断的通过SQL去调用基表的数据,查看是否中断
第三个是通过大量的DML操作,查看在线重定义的过程中,是否依然能够稳定运行。

我们初始化了一下的数据。
我们创建基表用户ref_owner,连接用户ref_conn
创建基表test_online_ref
## init
set echo on
create user ref_owner identified by oracle;
create user ref_conn identified by oracle;
grant connect,resource to ref_owner;
grant connect to ref_conn;
grant create synonym to ref_conn;

##owner account: ref_owner
conn ref_owner/oracle

CREATE TABLE test_online_ref 
   (  
   col1 varchar2(30),  
   col2 DATE  
   )  ; 
alter table    test_online_ref modify(col1 primary key);
生成近300万数据
insert into test_online_ref select level,sysdate+level*0.01 from dual connect by level<3000000;
commit;
grant select,delete,insert,update on ref_owner.test_online_ref to  ref_conn;
然后在连接用户创建同义词。
##connect account: ref_conn
conn ref_conn/oracle
create synonym ref_conn.test_online_ref for ref_owner.test_online_ref;
select count(*)from ref_conn.test_online_ref;
然后创建变更后的表。表结构信息可以根据需求来定义改变,比如从改一个普通表变为分区表。
conn ref_owner/oracle
CREATE TABLE new_ref  
   (  
   col1 varchar2(30),  
   col2 DATE  
   )  
   partition BY range(col2)  
   (  
   partition tab_part_1 VALUES less than (to_date('2016-10-01','yyyy-mm-dd')),  
   partition tab_part_2 VALUES less than (to_date('2017-10-01','yyyy-mm-dd')),  
   partition tab_part_3 VALUES less than (to_date('2018-10-01','yyyy-mm-dd')),
   partition tab_part_4 VALUES less than (to_date('2019-10-01','yyyy-mm-dd')),
   partition tab_part_maxvalue values less than (maxvalue)
   );  

grant select,delete  on ref_owner.new_ref    to ref_conn;

数据初始化完成,接下来我们需要做的是在线重定义了。
其实脚本就是下面的几行内容。
exec dbms_redefinition.can_redef_table('REF_OWNER','test_online_ref',1);  
exec  DBMS_REDEFINITION.CAN_REDEF_TABLE('REF_OWNER','test_online_ref',2);  
exec  DBMS_REDEFINITION.START_REDEF_TABLE('REF_OWNER','test_online_ref','new_ref',NULL,2);  
exec  DBMS_REDEFINITION.FINISH_REDEF_TABLE('REF_OWNER','test_online_ref','new_ref'); 

在线重定义的过程中,我们会并发调用开始所说的3个脚本来调用。然后观察是否会存在ORA的错误。
第一个场景的脚本如下:
function test_conn
{
sqlplus -s ref_conn/oracle <
set feedback off
set time on
col systimestamp format a35
select systimestamp,count(*)from test_online_ref;
EOF
}

for i in {1..1000000}
do
test_conn
done

剩下两个场景的脚本,套路都是类似的,通过频繁的DML或者查询来完成
比如查询
select systimestamp,count(*)from test_online_ref;
比如DML
delete from test_online_ref where rownum<2;
commit;

很快就测试完毕,查看日志没有任何的ORA错误。所以我们可以得到一个肯定的测试结果就是在线重定义是可信赖的。
得到的日志类似下面的形式:
我们可以从日志看到数据在极短的时间内发生变化依旧可以保持数据的可持续访问变更。尽管会出现一定的卡顿,从日志里看大概是3秒钟,但是业务访问不会中断。
SYSTIMESTAMP                          COUNT(*)
----------------------------------- ----------
18-SEP-16 10.49.53.769959 PM +08:00    2923035

SYSTIMESTAMP                          COUNT(*)
----------------------------------- ----------
18-SEP-16 10.49.53.898239 PM +08:00    2922896

SYSTIMESTAMP                          COUNT(*)
----------------------------------- ----------
18-SEP-16 10.49.56.325261 PM +08:00    2922722

SYSTIMESTAMP                          COUNT(*)
----------------------------------- ----------
18-SEP-16 10.49.56.454042 PM +08:00    2922599

变更完成后,原来的分区表new_ref就变成了普通表。
SQL> select dbms_metadata.get_ddl('TABLE','NEW_REF','REF_OWNER') from dual;      
  CREATE TABLE "REF_OWNER"."NEW_REF"
   (    "COL1" VARCHAR2(30),
        "COL2" DATE,
         PRIMARY KEY ("COL1")
。。。。
大家有问题可以补充,有些场景下还是值得提倡的。

关注DBAplus社群,了解更多技术干货文!