遷移目標java
按季度(每一個租戶自定義季度日期且各不相同)劃分,有明顯的冷熱數據區分,目標將冷數據分隔,減小單表過大,提供SQL等業務處理能力,期待預期按租戶自定義時間遷移,且遷移過程實現自動化,無需人工干預。sql
歸檔方案數據庫
按各租戶自定義中季度日曆進行遷移,熱數據保留最近四個季度的數據,其餘數據,以日曆中設定的春暑秋寒四個季度爲年,進行年維度的歷史數據歸檔。服務器
執行方案數據結構
定時任務,每日執行定時任務,判斷各個租戶當前所屬季度,判斷上一年的該季度數據是否已經完成遷移,無遷移記錄,則進行數據遷移。mybatis
一、動態的建立歸檔數據表,此過程須要可複用,以知足多個數據表遷移歸檔的需求ide
二、分校存在一個季度有兩種日曆的狀況,須要數據所有遷移不可遺留工具
三、遷移的數據明細須要被記錄,以此保證冪等,避免數據被重複遷移.net
核心邏輯過程code
一、判斷目標表是否存在,不存在則建立
select count(*) from information_schema.TABLES where table_name = #{tableName}
返回數據爲0,則證實數據表不存在,建立目標表
利用mybatis中${},將表名稱和數據結構傳入,進行建立
<update id="createTable"> create table ${tableName} ${content} </update>
二、批量數據遷移提高效率
1).INSERT INTO SELECT語句
語句形式爲:Insert into Table2(field1,field2,...) select value1,value2,... from Table1
要求目標表Table2必須存在,因爲目標表Table2已經存在,因此咱們除了插入源表Table1的字段外,還能夠插入常量。
2).SELECT INTO FROM語句
語句形式爲:SELECT vale1, value2 into Table2 from Table1
要求目標表Table2不存在,由於在插入時會自動建立表Table2,並將Table1中指定字段數據複製到Table2中
數據遷移以年爲單位,目標表Table2在遷移的時候必定是存在,故選用INSERT INTO SELECT方案,替代Insert INTO table(field1,field2,...) values(value1,value2,...)提高遷移效率,避免大量數據查詢再插入帶來應用服務器壓力
三、記錄已經遷移的數據(可複用)
CREATE TABLE `tb_move_data` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id', `biz_id` varchar(32) NOT NULL COMMENT '業務id', `city_code` varchar(8) NOT NULL COMMENT '租戶代碼', `table_name` varchar(32) NOT NULL COMMENT '表名', `num` int(11) NOT NULL COMMENT '遷移條數', `year` int(8) NOT NULL COMMENT '年', `term` int(8) NOT NULL COMMENT '季度', `start_time` datetime NOT NULL COMMENT '開始日期', `end_time` datetime NOT NULL COMMENT '截止日期', `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否刪除', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='數據遷移記錄';
利用insert into select 能夠獲取到遷移數據條數,將其餘業務信息拼接插入便可。
四、遷移完成後,移除原表中的已遷移數據,按期清理數據碎片。
歷史數據查詢處理
利用ShardingJdbc的分片策略,由於以年爲單位且歷史歸檔表中並沒存有關於year相關內容,能夠經過Hint指定分片值而非從SQL中提取分片值的方式進行分片的策略。
public class PlanHintStrategy implements HintShardingAlgorithm<String> { /** * * @param actualTables 物理表 * @param hintShardingValue 分片鍵,指定的表 * @return */ @Override public Collection<String> doSharding(Collection actualTables, HintShardingValue hintShardingValue) { List<String> shardingResult = new ArrayList<>(); actualTables.forEach(table -> { String tableName = (String) table; String suffix = tableName.substring(tableName.lastIndexOf("_") + 1); Collection<String> tableNames = hintShardingValue.getValues(); if (tableNames.contains(suffix)) { shardingResult.add(tableName); } }); return shardingResult; } }
在查詢以前先配置強制路由的分片便可
// Hint分片策略必需要使用 HintManager工具類 HintManager hintManager = HintManager.getInstance(); //查詢數據庫,能夠不配置 hintManager.addDatabaseShardingValue("tb_history_plan", 0); //查詢分片表,能夠配置多個 hintManager.addTableShardingValue("tb_history_plan", "2019"); hintManager.addTableShardingValue("tb_history_plan", "2020") // 直接指定對應具體的數據庫 hintManager.setDatabaseShardingValue(1);
關於hint策略推薦博客:https://blog.csdn.net/jobjava/article/details/106325053