分库分表历史数据迁移
概述
历史数据为一个时间点前的所有数据,是一个固定数量的记录。
对于历史数据迁移有两个比较粗略的方案:
- 运维团队提供数据库迁移工具,数据库层面直接迁移;
- 自己开发数据迁移程序,通过sql的方式进行迁移;
方案
方案一:运维工具
目前运维提供数据迁移只能实现整库或者整表的数据迁移,而分库分表需求中是要将一个单一库中数据迁移到多个不同的表中,所以运维的迁移不适用。
方案二:迁移程序(insert into … select * from)
迁移逻辑如下:
- 分页读取 sell_chance 表中的店铺号;
- 将读取的店铺号根据分表算法确定要迁移到的目标表 x ;
- 使用 insert into sell_chance_x select * from sell_chance where shop_code in (1, 2, …); 将同一个目标表的店铺一起迁移;
- 循环执行,直到查询不到店铺号。
方案三:迁移程序(insert into … select * from)
方案三与方案二的区别在于分表算法的计算迁移到了sql中;
迁移逻辑如下:
- 遍历分表数 x (0~39);
- 执行迁移sql: insert into sell_chance_x select * from sell_chance where CONVERT(**right**(shop_code, 3), SIGNED) mod 40 = x;
方案四:迁移程序 (insert into … () values (?,?),(?,?))
将程序分为读取和写入两部分,有不同线程处理;
迁移逻辑如下:
- 读线程:
- 分页读取 sell_chance 表中的店铺号;
- 根据店铺号分页读取数据(select * from sell_chance where shop_code=? limit m,n);
- 将读取的店铺号根据分表算法确定要迁移到的目标表 x ;
- 将数据存储到队列中(BlockingQueue);
- 循环执行,直到数据取完,发送结束信号。
- 写线程:
- 读取队列中(BlockingQueue)的数据;
- 保存数据(insert into sell_chance_x (…) values (?,…),(?,…));
- 循环读取,直到读取完毕且收到结束信号;
优化:并发读;写线程与目标表绑定,固定写一部分表去除并发写的情况。
性能测试
测试条件:
-Xmx4096m -Xms4096m
CPU:4c8t 3GHz
80605条数据为测试库;
19267385条数据为线上数据克隆库;
| 数据条数 | 方案2(ms) | 方案3(ms) | 方案4(ms) | 备注 |
|---|---|---|---|---|
| 80605 | 73216 | 32522(多线程) | 28175 | 有索引、InnoDB |
| 80605 | 79368 | 42250(单线程) | 36613 | 有索引、InnoDB |
| 80605 | 79953 | 22690(单线程) | 17787 | 无索引、MyISAM |
| 80605 | 85618 | 8418(多线程) | 17126 | 无索引、MyISAM |
| 80605 | 6903(多线程) | 18175 | 无索引、MyISAM | |
| 19267385 | 220291(多线程) | 4380463 | 无索引、MyISAM | |
| 19267385 | 347974(多线程) | 有索引、InnoDB |
选择
综合各个方案的实现与性能方面的考量,最终选择方案3,实现简单,且性能高。