需求:有一张表9亿多条数据,数据加索引总数据量61GB。考虑到这张表的大部分数据都不会再被使用并且大数据量可能影响整库的性能,所以决定将表里某一个时刻之前的数据备份到一张新表中,待备份完成后将旧表中已经备份的数据删除。由于数据量太大,不适合让DBA直接做备份。

  • 方案1

    main线程分页读取旧表数据,每页200条。每读取一页数据就新建一个线程,将200条数据交给新建的线程去完成insert到新表的操作。

弊端:需要将数据读到内存,然后再写回数据库,涉及到大量的IO操作。所有的数据都需要走网络,对网络带宽及稳定性要求很高。

  • 方案2

    直接使用SQL语句在MySQL端完成select和insert操作,不涉及IO操作。

弊端:在这种情况下,要分页操作就必须使用单线程。

综合考虑整个备份过程的速度与数据量,采用第二种方案。

涉及到的SQL语句如下:

<insert id="backupUniqueNumber" parameterClass="java.util.Map">
INSERT INTO UniqueNumber_backup_201603
(ID,
SerialNumber,
BusinessType,
AddTime
)
SELECT ID, SerialNumber, BusinessType, AddTime FROM UniqueNumber WHERE ID > #lastMaxId# limit #pageSize#
</insert> <!-- 强制走主库 -->
<select id="getLastMaxId" resultClass="java.lang.Integer">
/*+zebra:w*/SELECT MAX(ID) FROM UniqueNumber_backup_201603
</select>

主要的Java代码如下:

public class UniqueNumberBackupBiz {
private static final AvatarLogger logger = AvatarLoggerFactory.getLogger(UniqueNumberBackupBiz.class);
@Autowired
private UniqueNumberDao uniqueNumberDao; public void execute(){
int maxId = 932727664;// 932727664;//UniqueNumber表中2016-04-01 00:00:00数据的id为932727664
int lastMaxId = 0;
int pageSize = 300; try{
lastMaxId = uniqueNumberDao.getLastMaxId();
}catch (Exception e){
//这里出现异常是因为备份表中还没有数据,此时lastMaxId取默认值0. 这个异常只会在第一次运行时出现。
logger.warn(String.format("Get lastMaxId failed, system exit, please run the system manually"));
System.exit(0);
} long startTime = System.currentTimeMillis();
while(lastMaxId < maxId){
logger.info("lastMaxId=" + lastMaxId);
try {
uniqueNumberDao.backupUniqueNumber(lastMaxId, pageSize);
}catch (Exception e){
logger.error("backupUniqueNumber exception:", e);
}
try {
Thread.sleep(50);//防止MySQL压力过大
lastMaxId = uniqueNumberDao.getLastMaxId();
}catch (Exception e){
// logger.error("Thread sleep exception", e);
logger.error("Get lastMaxId failed, system exit, please run the system manually", e);
System.exit(0);
}
}
long endTime = System.currentTimeMillis();
logger.info(String.format("Data backup finished in %d ms", endTime - startTime));
}
}

为了防止对MySQL造成过大的压力,每一次循环中休眠50ms。运行中每秒insert的数据量大约5000条。若取消每次循环休眠50ms,每秒insert数据量大约为30000条。

PS:踩了一个坑,由于MySQL数据库有master slave之分,select操作是走slave库。master库与slave库同步存在一定的时差。之前没有强制select走master库,造成抛出了一些主键重复异常。不过这个异常不会造成多大的影响。后来强制select走主库就没有再抛出异常了。

数据全部从旧表搬到新表之后,需要将旧表中已备份的数据删除。

    <delete id="deleteOldData" parameterClass="java.util.Map">
<![CDATA[
DELETE FROM UniqueNumber
WHERE ID >= #startId# AND ID < #endId#
]]>
</delete> <!-- 强制走主库 -->
<select id="getMinId" resultClass="java.lang.Integer">
/*+zebra:w*/SELECT MIN(ID) FROM UniqueNumber
</select>
    public void deleteOldData(){
int startId = uniqueNumberDao.getMinId();
int pageSize = 1000;
int endId = startId + pageSize;
int maxId = uniqueNumberDao.getLastMaxId();
logger.info(String.format("maxId=%d", maxId));
while(endId < (maxId - 1000)){//保险起见,防止多删
try {
int num = uniqueNumberDao.deleteOldData(startId, endId);
Thread.sleep(50);
logger.info(String.format("startId=%d, endId=%d,%d rows deleted", startId, endId, num));
startId = endId;
endId = startId + pageSize;
}catch (Exception e){
logger.error("Error occurred when deleting data", e);
System.exit(-1);
}
}
}

删除任务执行完之后可能还剩下不到1000条数据没删完,需要手动执行delete语句来删除剩下的部分。

Java备份约9亿条数据的更多相关文章

  1. PostgreSQL中COUNT的各条件下(1亿条数据)例子

    test=# insert into tbl_time1 select generate_series(1,100000000),clock_timestamp(),now(); INSERT 0 1 ...

  2. 亿条数据在PHP中实现Mysql数据库分表100张

    当数据量猛增的时候,大家都会选择库表散列等等方式去优化数据读写速度.笔者做了一个简单的尝试,1亿条数据,分100张表.具体实现过程如下: 首先创建100张表: $i=0; while($i<=9 ...

  3. net.sz.framework 框架 ORM 消消乐超过亿条数据排行榜分析 天王盖地虎

    序言 天王盖地虎, 老婆马上生孩子了,在家待产,老婆喜欢玩消消乐类似的休闲游戏,闲置状态,无聊的分析一下消消乐游戏的一些技术问题: 由于我主要是服务器研发,客户端属于半吊子,所以就分析一下消消乐排行榜 ...

  4. 1亿条数据在PHP中实现Mysql数据库分表100张

    当数据量猛增的时候,大家都会选择库表散列等等方式去优化数据读写速度.笔者做了一个简单的尝试,1亿条数据,分100张表.具体实现过程如下: 首先创建100张表: $i=0; while($i<=9 ...

  5. oralce 超过1亿条数据的数据库表清理实践

    2018-08-18 16:58 无腿鸟 阅读(331) 评论(0) 编辑 收藏 问题:当一个表的数据量超过一亿条,要删除其中的5000w条,如何处理. 如果直接使用delete语句,会涉及到到大量的 ...

  6. java向数据库插入N条数据

    为了测试mysql的索引,要向数据库先插入上万条数据,然后再测试.手动插入太麻烦,写了一段代码. 先上代码: package action; import java.sql.Connection; i ...

  7. 演讲:对 2000 多亿条数据做一次 group by 需要多久?

    http://2017.qconbeijing.com/presentation/646?utm_source=weibo&utm_medium=infoq&utm_campaign= ...

  8. java 批量插入10万条数据

    for (int i = 0; i < 100000; i++) { dbHelper.insert("INSERT aaa(name) Values ('1')"); } ...

  9. 过千万、亿条数据的mysql表更新 mysql 线程状态

    分段更新 UPDATE question SET `status`=1 WHERE status!=1 LIMIT 3000;UPDATE answer SET `status`=1 WHERE st ...

随机推荐

  1. Top K 问题

    Example Given [3,10,1000,-99,4,100] and k = 3. Return [1000, 100, 10]. 解法有以下几种: 1. bubble sort k tim ...

  2. Android成长日记-使用GridView显示多行数据

    本节将实现以下效果 Ps:看起来很不错的样子吧,而且很像九宫格/se ----------------------------------------------------------------- ...

  3. hdu5175 gcd 求约数

    题意:求满足条件GCD(N,M) = N XOR M的M的个数 sol:和uva那题挺像的.若gcd(a,b)=a xor b=c,则b=a-c 暴力枚举N的所有约数K,令M=NxorK,再判断gcd ...

  4. [NOIP2014] 提高组 洛谷P2296 寻找道路

    题目描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点连通. 2 .在满足条 ...

  5. ecshop /pick_out.php SQL Injection Vul By Local Variable Overriding

    catalog . 漏洞描述 . 漏洞触发条件 . 漏洞影响范围 . 漏洞代码分析 . 防御方法 . 攻防思考 1. 漏洞描述 在进行输入变量本地模拟注册的时候,没有进行有效的GPC模拟过滤处理,导出 ...

  6. codevs 1051 接龙游戏(栈模拟)

    传送门 Description 给出了N个单词,已经按长度排好了序.如果某单词i是某单词j的前缀,i->j算一次接龙(两个相同的单词不能算接龙). 你的任务是:对于输入的单词,找出最长的龙. I ...

  7. django 模板中url的处理

    在模板中直接添加‘/home’这样的链接是十分不推荐的,因为这是一个相对的链接,在不同网页中打开可能会返回不一样的结果. 所以推荐的是 <a href="{{ object.get_a ...

  8. JavaScript 的错误(Error)与异常(Exception)处理

    PHP很少用到错误处理,因为框架帮了大忙,所以基本上没有主动接手过PHP的错误.PHP是偏后端的动态处理语言,和用户的关系不大,所以用户不会关心是否出现了报错.但是JavaScript就非常不同了,j ...

  9. Linux Basic --- The First Character in The File Properity

    -rw-r--r-- [d]: content [-]: file [l]: link file [b]: interface device for storage in a device file ...

  10. python 培训之HTTP

    1. urllib #!/usr/env/python # -*- coding:UTF-8 -*- from __future__ import print_function import sys ...