概述

历史数据为一个时间点前的所有数据,是一个固定数量的记录。

对于历史数据迁移有两个比较粗略的方案:

  1. 运维团队提供数据库迁移工具,数据库层面直接迁移;
  2. 自己开发数据迁移程序,通过sql的方式进行迁移;

方案

方案一:运维工具

目前运维提供数据迁移只能实现整库或者整表的数据迁移,而分库分表需求中是要将一个单一库中数据迁移到多个不同的表中,所以运维的迁移不适用

方案二:迁移程序(insert into … select * from)

迁移逻辑如下:

  1. 分页读取 sell_chance 表中的店铺号;
  2. 将读取的店铺号根据分表算法确定要迁移到的目标表 x
  3. 使用 insert into sell_chance_x select * from sell_chance where shop_code in (1, 2, …); 将同一个目标表的店铺一起迁移;
  4. 循环执行,直到查询不到店铺号。

方案三:迁移程序(insert into … select * from)

方案三与方案二的区别在于分表算法的计算迁移到了sql中

迁移逻辑如下:

  1. 遍历分表数 x (0~39);
  2. 执行迁移sql: insert into sell_chance_x select * from sell_chance where CONVERT(**right**(shop_code, 3), SIGNED) mod 40 = x;

方案四:迁移程序 (insert into … () values (?,?),(?,?))

将程序分为读取和写入两部分,有不同线程处理;

迁移逻辑如下:

  • 读线程:
    1. 分页读取 sell_chance 表中的店铺号;
    2. 根据店铺号分页读取数据(select * from sell_chance where shop_code=? limit m,n);
    3. 将读取的店铺号根据分表算法确定要迁移到的目标表 x
    4. 将数据存储到队列中(BlockingQueue);
    5. 循环执行,直到数据取完,发送结束信号。
  • 写线程:
    1. 读取队列中(BlockingQueue)的数据;
    2. 保存数据(insert into sell_chance_x (…) values (?,…),(?,…));
    3. 循环读取,直到读取完毕且收到结束信号;

优化:并发读;写线程与目标表绑定,固定写一部分表去除并发写的情况。

性能测试

测试条件:
-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,实现简单,且性能高。