使用在线重定义重构亿级分区表

简介: 在我的印象中,一直以来都会收到一封报警邮件,之前分析过,排查过,最后发现是一个遗留问题,协调开发同学,停业务维护还是有一些难度,最后不了了之了,在今天又突然想起了这件事情,觉得还是需要做点什么。

在我的印象中,一直以来都会收到一封报警邮件,之前分析过,排查过,最后发现是一个遗留问题,协调开发同学,停业务维护还是有一些难度,最后不了了之了,在今天又突然想起了这件事情,觉得还是需要做点什么。
报警邮件类似下面的形式: ZABBIX-监控系统:
------------------------------------
报警内容: Disk I/O is overloaded on 10.127.2.134_xx机房_xxxx
------------------------------------
报警级别: PROBLEM
------------------------------------
监控项目: CPU iowait time:17.21 %
------------------------------------
报警时间:2016.09.26-04:05:33
这是一台备库11gR2的环境,在ADG模式下的数据变化也会单独采样,这一点非常难得。所以很看到备库的DB time情况,可以明显看到在早间的时候有很大的抖动。

而基于快照,定位到具体的语句情况下,可见SQL_ID(4rhpc838qfsmy)就是我们要攻坚的重点了。

这是什么样的一个语句呢,让我很感意外。语句竟然看起来很简单,而且看起来竟然有两个执行计划。
$ sh showsqltext.sh 4rhpc838qfsmy
select * from (select user_ip,end_time from bill_logout_cn where cn=:1 order by end_time desc) where rownum=1
而且仔细看语句还是有一点优化的味道。 这样一个语句怎么性能会很差呢。
通过awrsqrpt得到的结果如下:

对这样一个语句,存在两个执行计划,就很奇怪了。

第一个执行计划虽然是索引扫描,但是I/O等待很高。
 
 Plan 2(PHV: 2814547617)
-----------------------

第二个执行计划产生了大量的buffer gets,使用了全表扫描。


  这是一个什么类型的表呢,数据量有2亿多,CN字段存在一个非唯一性索引。
执行计划如下

这个语句一个是使用了index skip scan,瓶颈在于扫描了大量的分区,结果大量的IO等待都在于此。
而第二个执行计划索性走了全表扫描,可见还是在运行中根据CBO评估而得全表的代价要相对低一些。

对于这个问题有几个疑问,首先这个语句性能如此之差,为什么在主库没有报警而在备库呢,其实原因是这样,主库的配置信息要好很多,这些问题和负载在主库都不是问题,以至于这个问题的影响在主库被弱化了。
而为什么语句走索引全扫描,全表扫描呢。这个其实说来话长,我查看了表的结构信息发现,这个表存在大量的分区,每天会生成一个分区,结果在2014年的某一天开始突然就停止了分区的维护,结果导致分区数据现在全都堆积在了默认分区上,这样就会性能一个很奇怪的数据分布,绝大多数的数据都分布在一个分区上,而还有很多历史数据分布在更多以日期为单位的分区上。
如果了解了问题的原委,其实也可以理解数据库在处理这个问题时的艰辛。
而对于这个问题的改进,就是需要重构分区,摆在我面前的由几件事情。首先是需要和开发确认是否历史数据可以清理,这个经过讨论,大家都带着保守态度;第二个问题是分区的维护,需要添加最近的一些分区,这个是否可以给出维护时间,不过经过讨论,在了解了业务特征之后,其实也可以做一个折中,那就是使用在线重定义来完成,尽管这是一个亿级数据的大表,但是因为是统计系统,所以数据更新很少,而且基本都是在凌晨胡统一更新,其他时段主要是查询为主,这样来看这个问题使用在线重定义其实还蛮不错的,互相成就,也不用互相协调区停业务应用了。
第二个问题解决之后第一个问题就好办了,可以在确认之后再具体部署。
好了,来到了重点的内容,那就是亿级大表的在线重定义,虽然之前做了周密的测试,但是还是有一些期待和小紧张。
和开发同学约定了下午的时间来在线维护,留给我的时间也不到一个小时了,要生成近900多个额外的分区,这个工作量着实不小,我采用了如下的SQL来动态生成需要补充的分区。
select 'PARTITION BILL_LOGOUT_CN_'||to_char((trunc(sysdate)-990+level),'yyyymmdd')||' VALUES LESS THAN (TO_DATE('||chr(39)||(trunc(sysdate)-990+level+1)||chr(39)||', '||chr(39)||'YYYY-MM-DD HH24:MI:SS'||chr(39)||'))  '
    ||'TABLESPACE ACCSTAT_DATA ,' from dual connect by level<990;
生成的语句类似下面的形式:
PARTITION BILL_LOGOUT_CN_20160924 VALUES LESS THAN (TO_DATE('2016-09-25 00:00:00', 'YYYY-MM-DD HH24:MI:SS'))  TABLESPACE ACCSTAT_DATA , 
。。。
我创建了一个新表BILL_LOGOUT_CN_DEF来和BILL_LOGOUT_CN最后做数据字典信息的交换。
在线重定义的前几步都是套路,因为没有主键,所以我使用rowid的方式。
exec  DBMS_REDEFINITION.CAN_REDEF_TABLE('TEST','BILL_LOGOUT_CN',2);  
exec  DBMS_REDEFINITION.START_REDEF_TABLE('TEST','BILL_LOGOUT_CN','BILL_LOGOUT_CN_DEF',NULL,2); 
第二步运行之后,后台就开始忙碌起来了。
可以看到有会话在运行这样的语句。
SQL_FULLTEXT
----------------------------------------------------------------------------------------------------
INSERT /*+ BYPASS_RECURSIVE_CHECK APPEND SKIP_UNQ_UNUSABLE_IDX */ INTO "TEST"."BILL_LOGOUT_CN_DEF"(M_ROW$$,"CN",XXXX) SELECT XXXX  FROM "TEST"."BILL_LOGOUT_CN" "BILL_LOGOUT_CN"                                                                   
而查看物化视图相关的数据字典,可以赫然看到有一个prebuilt物化视图,采用快速刷新的方式。

而在数据刷新之后,可以看到后台对于rowid的方式采用了下面的处理方式,即创建一个唯一性索引
SQL_FULLTEXT
----------------------------------------------------------------------------------------------------
 CREATE UNIQUE INDEX "TEST"."I_SNAP$_BILL_LOGOUT_CN_DEF" ON "TEST"."BILL_LOGOUT_CN_DEF" ("M_ROW$$")
  PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
  TABLESPACE "TEST_DATA"
而这个索引也在不断增大。
SEGMENT_NAME                      SIZE_M     BLOCKS
------------------------------ --------- ----------
I_SNAP$_BILL_LOGOUT_CN_DEF          8065    1032320
                               ---------
sum                                 8065
好了,有的同学可能会说,在线重定义了解那么多干嘛,够用就行了。
没过多久,就看到数据复制的过程抛错了。
SQL> exec  DBMS_REDEFINITION.START_REDEF_TABLE('TEST','BILL_LOGOUT_CN','BILL_LOGOUT_CN_DEF',NULL,2);  
BEGIN DBMS_REDEFINITION.START_REDEF_TABLE('TEST','BILL_LOGOUT_CN','BILL_LOGOUT_CN_DEF',NULL,2); END;

*
ERROR at line 1:
ORA-14010: this physical attribute may not be specified for an index partition
ORA-06512: at "SYS.DBMS_REDEFINITION", line 56
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1490
ORA-06512: at line 1
这个问题如果查看metalink,博客可能还没有很针对性的解答,这个就需要对在线重定义的过程很熟悉。
简单分析发现就是在表空间上出了问题。
重新分配扩展空间之后,再次开启重定义,会抛出下面的错误。
SQL> exec  DBMS_REDEFINITION.START_REDEF_TABLE('TEST','BILL_LOGOUT_CN','BILL_LOGOUT_CN_DEF',NULL,2);  
BEGIN DBMS_REDEFINITION.START_REDEF_TABLE('TEST','BILL_LOGOUT_CN','BILL_LOGOUT_CN_DEF',NULL,2); END;

*
ERROR at line 1:
ORA-23539: table "TEST"."BILL_LOGOUT_CN" currently being redefined
ORA-06512: at "SYS.DBMS_REDEFINITION", line 56
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1490
ORA-06512: at line 1
为了加快处理过程,我们也可以手工处理一部分
删除对应的物化视图和物化视图日志
SQL> drop materialized view test.BILL_LOGOUT_CN_DEF;
Materialized view dropped.
SQL> drop materialized view log on test.BILL_LOGOUT_CN;
Materialized view log dropped.
看来这个过程可以完全证明在线重定义是使用物化视图快速刷新的。
来终止一下重定义过程,重新来过。其实这个步骤就在做truncate的操作。
execute dbms_redefinition.ABORT_REDEF_TABLE ('TEST','BILL_LOGOUT_CN','BILL_LOGOUT_CN_DEF');
重新开始数据复制,重定义。
SQL> exec  DBMS_REDEFINITION.CAN_REDEF_TABLE('TEST','BILL_LOGOUT_CN',2);
SQL>exec  DBMS_REDEFINITION.START_REDEF_TABLE('TEST','BILL_LOGOUT_CN','BILL_LOGOUT_CN_DEF',NULL,2);  
这一次就顺利多了,一次搞定。
最后完成前可以再手工刷新一下增量数据,保持数据的gap尽可能小。
SQL> execute dbms_redefinition.sync_interim_table ('TEST','BILL_LOGOUT_CN','BILL_LOGOUT_CN_DEF');
PL/SQL procedure successfully completed.
最后交换数据字典信息即可完成。
SQL> exec  DBMS_REDEFINITION.FINISH_REDEF_TABLE('TEST','BILL_LOGOUT_CN','BILL_LOGOUT_CN_DEF');
PL/SQL procedure successfully completed.
Elapsed: 00:00:39.82
解决了之个问题之后,后续还有一些小的地方需要注意,补充新的分区,持续观察性能改进,历史分区数据的清理等。


目录
相关文章
|
6月前
|
SQL 存储 Oracle
线上数据问题排查案例分享-因为 HMS 和底层 orc 文件中某字段的数据精度不一致造成的数据丢失问题
线上数据问题排查案例分享-因为 HMS 和底层 orc 文件中某字段的数据精度不一致造成的数据丢失问题
|
3月前
|
存储 数据采集 缓存
TDengine 企业级功能:存储引擎对多表低频场景优化工作分享
在本文中,TDengine 的资深研发将对多表低频场景写入性能的大幅优化工作进行深入分析介绍,并从实践层面剖析本次功能升级的具体作用。
38 2
|
5月前
|
存储 关系型数据库 MySQL
太强了!三种方案优化 2000w 数据大表!
太强了!三种方案优化 2000w 数据大表!
|
6月前
|
关系型数据库 MySQL 数据库
107分布式电商项目 - MySQL优化(数据库结构优化)
107分布式电商项目 - MySQL优化(数据库结构优化)
39 0
|
7月前
|
SQL 关系型数据库 MySQL
浅谈千万级系统重构系列
浅谈千万级系统重构系列
60 0
OushuDB 产品基本介绍——表(下)
OushuDB 产品基本介绍——表(下)
44 0
|
存储 SQL NoSQL
OushuDB 产品基本介绍——表(上)
OushuDB 产品基本介绍——表
68 0
|
SQL BI 索引
【SQL开发实战技巧】系列(二十八):数仓报表场景☞人员分布问题以及不同组(分区)同时聚集如何实现
【SQL开发实战技巧】这一系列博主当作复习旧知识来进行写作,毕竟SQL开发在数据分析场景非常重要且基础,面试也会经常问SQL开发和调优经验,相信当我写完这一系列文章,也能再有所收获,未来面对SQL面试也能游刃有余~。
【SQL开发实战技巧】系列(二十八):数仓报表场景☞人员分布问题以及不同组(分区)同时聚集如何实现
|
消息中间件 运维 监控
200张表,单表记录过亿,10多年核心老系统的重构之旅
200张表,单表记录过亿,10多年核心老系统的重构之旅
390 0
200张表,单表记录过亿,10多年核心老系统的重构之旅
|
数据库 索引 大数据
这才是真正的表扩展方案
事情变得有意思了,上一篇花1小时撰写的“一分钟”文章,又引起了广泛的讨论,说明相关的技术大家感兴趣,挺好。第一次一篇技术文章的评论量过100,才知道原来“评论精选”还有100上限,甚为欣慰(虽然是以一种自己不愿看到的方式)。
594 0