Java备份约9亿条数据
需求:有一张表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亿条数据的更多相关文章
- PostgreSQL中COUNT的各条件下(1亿条数据)例子
test=# insert into tbl_time1 select generate_series(1,100000000),clock_timestamp(),now(); INSERT 0 1 ...
- 亿条数据在PHP中实现Mysql数据库分表100张
当数据量猛增的时候,大家都会选择库表散列等等方式去优化数据读写速度.笔者做了一个简单的尝试,1亿条数据,分100张表.具体实现过程如下: 首先创建100张表: $i=0; while($i<=9 ...
- net.sz.framework 框架 ORM 消消乐超过亿条数据排行榜分析 天王盖地虎
序言 天王盖地虎, 老婆马上生孩子了,在家待产,老婆喜欢玩消消乐类似的休闲游戏,闲置状态,无聊的分析一下消消乐游戏的一些技术问题: 由于我主要是服务器研发,客户端属于半吊子,所以就分析一下消消乐排行榜 ...
- 1亿条数据在PHP中实现Mysql数据库分表100张
当数据量猛增的时候,大家都会选择库表散列等等方式去优化数据读写速度.笔者做了一个简单的尝试,1亿条数据,分100张表.具体实现过程如下: 首先创建100张表: $i=0; while($i<=9 ...
- oralce 超过1亿条数据的数据库表清理实践
2018-08-18 16:58 无腿鸟 阅读(331) 评论(0) 编辑 收藏 问题:当一个表的数据量超过一亿条,要删除其中的5000w条,如何处理. 如果直接使用delete语句,会涉及到到大量的 ...
- java向数据库插入N条数据
为了测试mysql的索引,要向数据库先插入上万条数据,然后再测试.手动插入太麻烦,写了一段代码. 先上代码: package action; import java.sql.Connection; i ...
- 演讲:对 2000 多亿条数据做一次 group by 需要多久?
http://2017.qconbeijing.com/presentation/646?utm_source=weibo&utm_medium=infoq&utm_campaign= ...
- java 批量插入10万条数据
for (int i = 0; i < 100000; i++) { dbHelper.insert("INSERT aaa(name) Values ('1')"); } ...
- 过千万、亿条数据的mysql表更新 mysql 线程状态
分段更新 UPDATE question SET `status`=1 WHERE status!=1 LIMIT 3000;UPDATE answer SET `status`=1 WHERE st ...
随机推荐
- retinajs 使用方法
本文根据retinajs的官网翻译,如果有翻译错的地方,还请朋友指正.谢谢. 工作原理: 现在有4种方式: 1.自动交换“img”标签的"src"路径. 2.在内联样式中自动交换背 ...
- Linux网卡的相关配置总结
当有多个网卡的时候,我们需要进行相关的配置. 一.如何改变网卡的名字? 修改/etc/udev/rules.d/70-persistent-net.rules 进去之后的效果是 根据mac地址,把没用 ...
- 79.Android之动画基础
转载:http://a.codekk.com/detail/Android/lightSky/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8 ...
- Jquery实现滚动到底部加载更多(最原始)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...
- css选择器([class*=" icon-"], [class^=icon-] 的区别)
官方解释: [attribute^=value],a[src^="https"],选择其 src 属性值以 "https" 开头的每个 <a> 元素 ...
- BeautifulSoup高级应用 之 CSS selectors /CSS 选择器
BeautifulSoup支持最常用的CSS selectors,这是将字符串转化为Tag对象或者BeautifulSoup自身的.select()方法. 本篇所使用的html为: html_doc ...
- python pep8
有这个自动的规范检查工具 pip install pep8 具体使用不说了 ==. 百度一堆 http://blog.sae.sina.com.cn/archives/4781 看这里
- 【Beta版本】冲刺-Day3
队伍:606notconnected 会议时间:12月11日 目录 一.行与思 二.站立式会议图片 三.燃尽图 四.代码Check-in 一.行与思 张斯巍(433) 今日进展:学习了很多androi ...
- .net 运用YUI相关的dll压缩js (按照自己的规则,想想都觉得强大和有趣)
写在前面 不管是做前端的还是做后台的,不管是懂javaScript的还是不太懂JavaScript的人,我想都或多或想的知道些许js压缩对于页面性能提升的效应吧. 之前老喜欢用在线压缩工具去压缩js, ...
- Docker入门教程(六)另外的15个Docker命令
Docker入门教程(六)另外的15个Docker命令 [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第六篇,继续介绍Docker命令.之前的第二篇文章 ...