将数据从一张表中迁移到另一张表中,在数据量少的情况下很容易实现,而且方法也有很多,但当数据量到了百万、千万级时,不同方法在效率上会有很大差别。
业务场景
项目在运行时会存储实时数据,主表每秒插入2,3条数据,一条主数据对应10条左右明细数据,现在数据库中,主表1千万条,明细8千万;需求是要根据主表中的type
字段进行分类,将主表和明细表拆再拆出2张表。
实现
项目在运行,实时会有数据存入,所以分为3个阶段;原表alarm
为主表,alarm_detail
为明细表;
1、将数据按类型从原表中导出为文件,再导入到对应的新建表中
2、项目暂停,执行替换sql,更新代码,重启项目
3、将在导入导出期间产生的数据再次按类型插入到新表中
一、项目正常运行,代码未更新
复制alarm 与 alarm_detail 表
1 | CREATE TABLE alarm_copy1 LIKE alarm; |
新建alarm_2表与明细表alarm_2_detail
1 | CREATE TABLE `alarm_2` ( |
获取原表主键最大id
1 | SELECT @maxId:=MAX(id) FROM alarm; |
导出出A类型主数据,再导入新表
FIELDS TERMINATED BY ','
表示字段间用,
分割
OPTIONALLY ENCLOSED BY '"'
表示所有字符用"
包裹
ESCAPED BY '*'
表示用*
代表转义字符
LINES TERMINATED BY '\r\n'
表示每条数据用空格加回车结束
1 | SELECT * FROM alarm WHERE id<@maxId AND type='A' INTO OUTFILE 'alarm_2.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '*' LINES TERMINATED BY '\r\n'; |
导出出A类型明细数据,再导入新表
1 | SELECT ad.* FROM alarm_detail ad WHERE EXISTS (SELECT iotId FROM alarm a WHERE ad.iotId=a.id) INTO OUTFILE 'alarm_2_detail.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '*' LINES TERMINATED BY '\r\n'; |
导出出B类型主数据,再导入copy表
1 | SELECT * FROM alarm WHERE id<@maxId AND type='A' INTO OUTFILE 'alarm_copy1.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '*' LINES TERMINATED BY '\r\n'; |
导出出B类型明细数据,再导入新表
1 | SELECT ad.* FROM alarm_detail ad WHERE EXISTS (SELECT iotId FROM alarm_copy1 ac WHERE ac.iotId=ad.id) INTO OUTFILE 'alarm_detail_copy1.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '*' LINES TERMINATED BY '\r\n'; |
二、项目暂停、更新代码
项目需要暂停几分钟,修改表名并更新代码
修改表名称
将*_copy1表名与原表互换
1 | ALTER TABLE alarm RENAME TO alarm_temp; |
修改自增数
为了保证在新数据插入新表后不会与暂未拆分数据主键冲突,需要将所有表的自增值改为原表自增数大小,
1 | #创建存储过程修改自增值 |
修改alarm
、alarm_detail
、alarm_2
、alarm_2_detail
的自增数(大于原表目前的自增数值即可)
1 | #调用 |
查询已拆分数据的最大id,并记录
1 | SELECT @maxId:=MAX(a.id) MAXId FROM( |
三、代码更新完成,项目启动
现在在*_copy1表中还有未拆分的数据,现在再进行拆分
创建拆分存储过程
1 | DROP PROCEDURE IF EXISTS post_alarm_split; |
执行拆分
@maxId
为之前已拆分过数据的最大主键id+1
1 | #后置拆分 |
总结
1、这种拆分方式适合主键id
自增的情况
2、项目重启后的拆分也可以使用导入导出的方式拆,重点是记录好已拆分的id
3、利用导出导入的方式可以大大提高数据迁移的效率
4、如果预计某些表数据量会很大时,可以考虑在表创建时就进行分区、或分表
备注
导出时生成的文件在mysql的Data目录下,可以删除,节省服务器存储空间