Mysql大表数据归档实现方案

 更新时间:2024年11月13日 10:52:45   作者:RobinCode  
本文介绍了MySQL大表数据归档,通过创建历史订单表并基于主键id进行分批处理,避免影响线上业务和产生慢SQL,下面就来详细的介绍一下,感兴趣的可以了解一下

前言

在生产实践中,你的mysql数据库可能面临下面这些情况:

  • 不可抗力的因素,数据库所在服务器被回收,或者服务器磁盘损坏,数据库必须得迁移?
  • 单点数据库读写压力越来越大,需要扩展一个或多个节点分摊读写压力?
  • 单表数据量太大了,需要进行水平或垂直拆分怎么搞?
  • 数据库需要从mysql迁移到其他数据库,比如PG,OB…

以上的这些场景,对于不少同学来讲,或多或少的在所处的业务中可能会涉及到,没有碰到还好,一旦发生了这样的问题,该如何处理呢?在这里我通过提供一个思路来解决单表数据量太大了,进行水平拆分,将历史数据归档保证热点数据查询

归档流程示意图

在这里插入图片描述

实现步骤

controller 层

@Slf4j
@RestController
@RequestMapping("/backDoor")
public class CleanHistoryDataController {

    @Autowired
    private ICleanHistoryDataService cleanHistoryDataService;

    /**
     * 把指定过期时间的订单表数据迁移到历史表中
     */
    @PostMapping("/cleanByTableNameAndEndTime")
    public Resp<String> cleanByTableNameAndEndTime(@RequestBody CleanTableReq cleanTableReq) {
        try {
            CleanTableBo cleanTableBo = ObjectUtils.mapValue(cleanTableReq, CleanTableBo.class);
            cleanHistoryDataService.cleanByTableNameAndEndTime(cleanTableBo);
        } catch (Exception e) {
            log.error(cleanTableReq.getTableName() + " 数据迁移异常", e);
        }
        return Resp.success("success");
    }
}

Service 层

public interface ICleanHistoryDataService {

    void cleanHistoryTableData();
}
import com.alibaba.fastjson.JSONObject;
import com.photon.union.risk.clean.service.ICleanHistoryDataService;
import com.photon.union.risk.repo.mapper.clean.MasterDbMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.util.List;
import java.util.stream.Collectors;


/**
 * @author robin
 */
@Service
@Slf4j
public class CleanHistoryDataService implements ICleanHistoryDataService {
    @Autowired
    private MasterDbMapper masterDbMapper;

    @Override
    public void cleanHistoryTableData() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        int logInt = 0;
        Long startId = 0L;
        while (true) {
            logInt ++;
            List<JSONObject> hashMapList = masterDbMapper.selectHistoryTableDataIds(startId);
            if (CollectionUtils.isEmpty(hashMapList)){
                break;
            }
            List<Long> allIds = hashMapList.stream().map(o -> o.getLong("id")).collect(Collectors.toList());
            startId = allIds.get(allIds.size()-1);
            if (logInt % 100 == 0 ){
                log.info("id 已经处理到-->" + allIds.get(allIds.size()-1));
            }
            try {
                // 往归档历史数据表写入数据
                masterDbMapper.insertOldHistoryTableDataBatchByIds(allIds);
                // 把归档的数据从目前业务表中删除
                masterDbMapper.deleteHistoryTableDataBatchByIds(allIds);
            }catch (Exception e){
                log.error("数据迁移异常,ids:{}", allIds, e);
            }
        }
        stopWatch.stop();
        log.info("数据迁移到历史表处理完成时间:{}s", (long)stopWatch.getTotalTimeSeconds());
    }
}

Mapper 层

import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @author robin
 */
@Repository
public interface MasterDbMapper {

    List<JSONObject> selectHistoryTableDataIds( @Param("id") Long startId);

    void insertOldHistoryTableDataBatchByIds(@Param("ids") List<Long> allIds);

    void deleteHistoryTableDataBatchByIds(@Param("ids") List<Long> allIds);
}

Sql Mapper

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.MasterDbMapper">

    <insert id="insertOldHistoryTableDataBatchByIds">
        INSERT IGNORE INTO t_order_old
        SELECT NULL,order_no,created_at
        FROM t_order WHERE id in
        <foreach collection="ids" item="item" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </insert>

    <delete id="deleteHistoryTableDataBatchByIds">
        DELETE FROM t_order WHERE id IN
        <foreach collection="ids" item="item" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </delete>

    <select id="selectHistoryTableDataIds" resultType="com.alibaba.fastjson.JSONObject">
        SELECT id FROM t_order
        WHERE id > #{id} and created_at lt;= DATE_SUB(NOW(), INTERVAL 6 MONTH)
        ORDER BY id limit 1000
    </select>

</mapper>


核心说明

  • 根据 t_order订单表结构创建 t_order_old历史订单表用于历史数据备份存放。
  • 整个流程基于主键 id 处理,避免慢 sql 产生,做到不影响当前线上业务处理。
  • 1000 条记录一个批次,避免长期抢占锁资源,同时每个批次执行不影响下个批次处理,出现异常后,打印 error 日志再人工跟进处理。

总结

上述方案是处理历史数据归档的一种方式,到此这篇关于Mysql大表数据归档实现方案的文章就介绍到这了,更多相关Mysql大表数据归档内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL中CONCAT()函数拼接出现NULL的问题解决

    MySQL中CONCAT()函数拼接出现NULL的问题解决

    本文主要介绍了MySQL中CONCAT()函数拼接出现NULL的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • MySQL中Join的算法(NLJ、BNL、BKA)详解

    MySQL中Join的算法(NLJ、BNL、BKA)详解

    这篇文章主要介绍了MySQL中Join的算法(NLJ、BNL、BKA)详解,Join是MySQL中最常见的查询操作之一,用于从多个表中获取数据并将它们组合在一起,本文将探讨这两种算法的工作原理,以及如何在MySQL中使用它们
    2023-07-07
  • MySQL字符之char、varchar类型简析

    MySQL字符之char、varchar类型简析

    varchar和char是MySQL中的两种数据类型,都是用来存储字符串的,下面这篇文章主要给大家介绍了关于MySQL字符之char、varchar类型的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • MySQL 全文索引的原理与缺陷

    MySQL 全文索引的原理与缺陷

    这篇文章主要介绍了MySQL 全文索引的原理与缺陷,帮助大家更好的理解和使用MySQL中的索引,感兴趣的朋友可以了解下
    2020-12-12
  • 用MySQL创建数据库和数据库表代码

    用MySQL创建数据库和数据库表代码

    了解了一些最基本的操作命令后,我们再来学习如何创建一个数据库和数据库表。
    2008-10-10
  • MYSQL 数据库导入导出命令

    MYSQL 数据库导入导出命令

    在不同操作系统或MySQL版本情况下,直接拷贝文件的方法可能会有不兼容的情况发生。所以一般推荐用SQL脚本形式导入。下面分别介绍两种方法。
    2010-11-11
  • Mysql触发器字段双向更新方式

    Mysql触发器字段双向更新方式

    这篇文章主要介绍了Mysql触发器字段双向更新方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • linux下mysql链接被防火墙阻止的解决方法

    linux下mysql链接被防火墙阻止的解决方法

    linux下安装了mysql,不能从其它机器访问 帐号已经授权从任意主机进行访问
    2012-07-07
  • mysql忘记密码重置的方法实现

    mysql忘记密码重置的方法实现

    本文主要介绍了mysql忘记密码重置的方法实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • mysql服务启动不了解决方案

    mysql服务启动不了解决方案

    最近在Windows 2003上的MySQL出现过多次正常运行时无法连接数据库故障,现象是无法连接数据库,也无法停止MySQL或重启MYSQL,由于每次都是草草尝试各种方法搞定即可本文将详细介绍解决方法
    2012-11-11

最新评论