问题描述
生产库上关注表(focus),目前单表数据量级去到了1600w条。但很多是无效的数据,实际有用的数据是半年。通过分区的方式来优化这个表,加速数据查询速度。
操作过程思路
新建一张分区表,以flg_date字段来进行分区选择,以一个季度的数据分一个区。然后把旧表的数据导入到新表,修改旧表表名,再把新表改回旧表的名字。
以flg_date字段进行分区,在DAO层的查询中,select共出现18次,查询条件带flg_date的,出现9次。
试验环境(虚拟机)
mysql版本:5.6.40
操作系统:Linux CentOS-7.0
内存:1G
内核:1
硬盘:20G
创建分区表(csmbp_flight_focus_p)
因默认分区限制分区字段必须是主键(PRIMARY KEY)的一部分,需要把id 、flt_date一起设为该表主键,使用联合主键。focus表结构中,有7个索引,1个主键索引,一个普通索引,5个组合索引,新建的分区表,暂不加入旧表中的索引。按季度分区,一次分十年。
查看分区表
|
|
添加测试数据(focus)
使用存储过程插入非空字段的数据,插入1600W条数据。
旧表数据转移至新的分区表
|
|
总耗时12分6秒。
再次查看分区的存储记录情况:
验证查询对比
- 查focus表:耗时2分54秒12SELECT * FROM focus f WHERE f.flt_date >= '2017-12-16 00:00:00'AND f.flt_date <= '2018-11-08 00:00:00';
- 查focus_p表:耗时28秒12SELECT * FROM focus_p f WHERE f.flt_date >= '2017-12-16 00:00:00'AND f.flt_date <= '2018-11-08 00:00:00';
分区管理
- 删除分区:ALTER TABLE focus_p DROP PARTITION p1;
- 分区合并:ALTER TABLE focus_p REORGANIZE PARTITION p1,p2 INTO (PARTITION p1 VALUES LESS THAN (TO_DAYS(‘20180401’)));
- 新增分区:ALTER TABLE focus_p ADD PARTITION (PARTITION p_12 VALUES LESS THAN (TO_DAYS(‘20180401’)));
- 新增分区注意:因原先最后一个分区是PARTITION p_11 VALUES LESS THAN MAXVALUE; 那么应该先合并一个分区再删除被合并的分区,然后在执行新增分区语句,分区名就用被合并的那个分区名;
修改表名
先修改旧表名,再把旧表名修改成新表名。
存在的风险
- 数据完整性的保障和耗时,存在一定的不可控。在把数据转移至新分区表时,服务一直在使用,就会出现在转移数据到完成数据转移的时间间隔中,出现新增数据在旧表上,而新表没有的情况。可以考虑在新表插入完旧表的数据后,做一个count(*)操作,先记录新表刚开始有多少数据量,再新表投入使用后,再count一下旧表的数据,count旧表减去count新表,代表之间的差值,用mysql提供的limit语法,把剩余的差值转移至分区表中。select * from table limit m,n。m表示指定从第几条数据开始取,n表示取多少条数据。因m的数值是从0开始的,所以m=count(*)即可,不用减1。从旧表中指定位置开始导入,n可以取旧表与新表之间的差值。整个数据转移的过程中,测试实验出的时间是总耗时12分6秒,生产环境还是会存在不确定性。
- 在新表表名替换过程中,服务不中断的情况下,有可能出现,已有事务正在向旧表提交请求。可以考虑不更改表名的操作,而在工程项目中的代码中,更改实体类所映射的表名。
- 新分区表是否需要加上旧表中的索引。
- 旧表数据是否需要删除。不建议删除,旧表数据的带有7个索引,DROP操作会产生较长的耗时,具体未验证过。可以考虑把它作为一个备份数据存在。
开启mysql定时任务
检查event事件是否开启:SHOW VARIABLES LIKE ‘event_scheduler’;
OFF则需要开启:SET GLOBAL event_scheduler = ON;
创建定时创建分区SQL
|
|
资源使用情况
- 空闲时:
- 执行数据转移时:CPU使用率在30%-70%之间,内存占用率40%左右