Mysql批量插入对比(附github仓库demo)

2023-05-16

前言

本文记录个人使用MySQL插入大数据总结较实用的方案,通过对常用插入大数据的4种方式进行测试,

  • for循环单条
  • 拼接SQL
  • 批量插入saveBatch()
  • 循环 + 开启批处理模式
    最近趁空闲之余,在对MySQL数据库进行插入数据测试

准备工作

测试环境:SpringBoot项目、MyBatis-Plus框架、MySQL5.7、JDK8
前提:SpringBoot项目集成MyBatis-Plus上述文章有配置过程,同时实现IService接口用于进行批量插入数据操作saveBatch()方法

创建springboot项目和数据库

github:demo代码地址
maven依赖
pom

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springboot-demo</artifactId>
        <groupId>com.cainiao</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springboot-save-batch</artifactId>
    <packaging>jar</packaging>

    <name>springboot-save-batch</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.34</version>
        </dependency>
        <!--mybatisPlus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
            <scope>compile</scope>
        </dependency>
        <!--lombok :getter/setter方法以及构造器的生成 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 引入阿里数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

applocation.yml


# 配置端口
server:
  port: 8089
  servlet:
    context-path: /caimiao
spring:
  # 配置数据源
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/cainiao?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&sessionVariables=sql_mode=NO_ENGINE_SUBSTITUTION
    username: root
    password: 123456
#    type: com.alibaba.druid.pool.DruidDataSource
#  druid:
#    initialSize: 5 #初始化连接大小
#    minIdle: 5     #最小连接池数量
#    maxActive: 20  #最大连接池数量
#    maxWait: 60000 #获取连接时最大等待时间,单位毫秒
#    timeBetweenEvictionRunsMillis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
#    minEvictableIdleTimeMillis: 300000   #配置一个连接在池中最小生存的时间,单位是毫秒
#    validationQuery: SELECT 1 from DUAL  #测试连接
#    testWhileIdle: true                  #申请连接的时候检测,建议配置为true,不影响性能,并且保证安全性
#    testOnBorrow: false                  #获取连接时执行检测,建议关闭,影响性能
#    testOnReturn: false                  #归还连接时执行检测,建议关闭,影响性能
#    poolPreparedStatements: false        #是否开启PSCache,PSCache对支持游标的数据库性能提升巨大,oracle建议开启,mysql下建议关闭
#    maxPoolPreparedStatementPerConnectionSize: 20 #开启poolPreparedStatements后生效
#    filters: stat,wall,log4j #配置扩展插件,常用的插件有=>stat:监控统计  log4j:日志  wall:防御sql注入
#    connectionProperties: 'druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000' #通过connectProperties属性来打开mergeSql功能;慢SQL记录


# mybatis-plus相关配置
mybatis-plus:
  # xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
  mapper-locations: classpath:mapper/*.xml
  # 以下配置均有默认值,可以不设置
  global-config:
    db-config:
      #主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
      id-type: auto
      #字段策略 IGNORED:"忽略判断"  NOT_NULL:"非 NULL 判断")  NOT_EMPTY:"非空判断"
      field-strategy: NOT_EMPTY
      #数据库类型
      db-type: MYSQL
  configuration:
    # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
    map-underscore-to-camel-case: true
    # 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
    call-setters-on-nulls: true
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

swagger:
  enable: true

实验数据库表创建

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `addr` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


开始测试

简明:完成准备工作后,即对for循环、拼接SQL语句、批量插入saveBatch()、循环插入+开启批处理模式,该4种插入数据的方式进行测试性能。

向数据库中插入5w条数据

for循环

@GetMapping("for")
    public void saveStudent(){
        // 开始时间
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 50000; i++){
            Student student = new Student();
            student.setName("张三" + i);
            student.setAge(i);
            student.setAddr("北京市第"+i+"街道");
            studentDao.insert(student);
        }
        // 结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("插入数据消耗时间:" + (endTime - startTime));
    }

执行耗时:222080 大约222秒
在这里插入图片描述

拼接sql

简明:拼接格式:insert into student(xxxx) value(xxxx),(xxxx),(xxxxx)…

@ApiOperation("sql批量插入")
    @GetMapping("sql")
    public void saveSqlStudent(){
        // 开始时间
        long startTime = System.currentTimeMillis();
        List<Student> studentList = new ArrayList<>();
        for (int i = 0; i < 50000; i++){
            Student student = new Student();
            student.setName("李四" + i);
            student.setAge(i);
            student.setAddr("北京市第"+i+"街道");
            studentList.add(student);
        }
        studentDao.saveList(studentList);
        // 结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("插入数据消耗时间:" + (endTime - startTime));
    }

Dao:

void saveList(@Param("list") List<Student> studentList);

mapper.xml

 <insert id="saveList">
        INSERT INTO student(name,age,addr)  VALUES
        <foreach collection="list" item="item" index="index" separator=",">
        (#{item.name},
        #{item.age},
        #{item.addr})
        </foreach>

    </insert>

执行时间:2971 大约2.9秒

在这里插入图片描述

总结:拼接结果就是将所有的数据集成在一条SQL语句的value值上,其由于提交到服务器上的insert语句少了,网络负载少了,性能也就提上去。

但是当数据量上去后,可能会出现内存溢出、解析SQL语句耗时等情况,但与第一点相比,提高了极大的性能。

批量插入saveBatch

简明:使用MyBatis-Plus实现IService接口中批处理saveBatch()方法,对底层源码进行查看时,可发现其实是for循环插入,但是与第一点相比,为什么性能上提高了呢?因为利用分片处理(batchSize = 1000) + 分批提交事务的操作,从而提高性能,并非在Connection上消耗性能。

  @ApiOperation("batch批量插入")
    @GetMapping("batch")
    public void saveBatchStudent(){
        // 开始时间
        long startTime = System.currentTimeMillis();
        List<Student> studentList = new ArrayList<>();
        for (int i = 0; i < 50000; i++){
            Student student = new Student();
            student.setName("李四" + i);
            student.setAge(i);
            student.setAddr("北京市第"+i+"街道");
            studentList.add(student);
        }
        studentDao.saveList(studentList);
        // 结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("插入数据消耗时间:" + (endTime - startTime));
    }

执行时间:118409秒 约118秒
在这里插入图片描述
重点注意:MySQL JDBC驱动默认情况下忽略saveBatch()方法中的executeBatch()语句,将需要批量处理的一组SQL语句进行拆散,执行时一条一条给MySQL数据库,造成实际上是分片插入,即与单条插入方式相比,有提高,但是性能未能得到实质性的提高。

所以需要数据库链接开启rewriteBatchedStatements = true
我们开启之后再执行一遍:

    url: jdbc:mysql://localhost:3306/cainiao?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&useSSL=false&serverTimezone=GMT%2B8&sessionVariables=sql_mode=NO_ENGINE_SUBSTITUTION

执行时间:85155 约85秒
在这里插入图片描述

循环插入 + 开启批处理模式(总耗时:1.7秒)(重点:一次性提交)

@ApiOperation("forSaveBatch批量插入")
    @GetMapping("/forSaveBatch")
    public void forSaveBatch(){
        //  开启批量处理模式 BATCH 、关闭自动提交事务 false
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
        //  反射获取,获取Mapper
        StudentDao studentMapper = sqlSession.getMapper(StudentDao.class);
        long startTime = System.currentTimeMillis();
        for (int i = 0 ; i < 50000 ; i++){
            Student student = new Student();
            student.setName("王五" + i);
            student.setAge(i);
            student.setAddr("北京市第"+i+"街道");
            studentMapper.insert(student);
        }
        // 一次性提交事务
        sqlSession.commit();
        // 关闭资源
        sqlSession.close();
        long endTime = System.currentTimeMillis();
        System.out.println("总耗时: " + (endTime - startTime));
    }

执行时间:99530 约99秒
在这里插入图片描述

总结

MySQL插入大数据一些方案心得,可得知主要是在获取连接、关闭连接、释放资源和提交事务等方面较耗能,其中最需要注意是开启批处理模式,即URL地址的参数:rewriteBatchedStatements = true,否则也无法发挥作用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mysql批量插入对比(附github仓库demo) 的相关文章

随机推荐

  • 手把手教你新建一个winform项目(史上最全)

    文章目录 前言 xff1a 第1步 打开Microsoft Visual Studio xff08 简称vs xff09 xff0c 本人这里使用的是Visual Studio 2017 专业版 xff0c 如下图 xff1a 1 2 Vi
  • 2021-01-20

    中文字库液晶模块12864示例程序范例 xff1a 液晶屏型号 xff1a JLX12864G 086 PC 3S 接口 xff1a 串行 中文字库 xff1a 带中文字库IC JLX GB2312 竖置横排 驱动IC UC1701X 与S
  • 前端开发中常见的浏览器兼容性问题及解决方案

    文章目录 前言一 浏览器四大内核二 主流兼容问题 xff08 一 xff09 浏览器引擎 xff08 二 xff09 兼容问题的原因 xff08 三 xff09 为什么浏览器会存在兼容性问题 xff08 四 xff09 处理兼容问题的思路1
  • 论文复现——Sphereface-Pytorch

    最近在写论文 xff0c 要做一些对比实验 xff0c 需要以Sphereface为基础 其实实验早该做了 xff0c 就是一直拖拖拖 唉拖延症患者 今天总算是把github上的代码跑通了 xff0c 赶紧做下小笔记 因为还要赶论文 xff
  • mysql学习-9.如何正确的使用索引

    1 索引的规则 1 1 等值匹配 假设索引 A select from table where A 61 xxx就是走索引的 1 2 最左侧列匹配 假设索引 A B select from table where A 61 xxx and
  • Python/matplotlib之【RuntimeWarning: More than 20 figures have been opened】

    Python matplotlib之 RuntimeWarning More than 20 figures have been opened 当绘图的过程中 xff0c 建立了大量的figure xff0c 就会报错 解决的方法 xff0
  • 【学习】《软件工程》期末考试卷A+参考答案

    2021 福师网院 软件工程 2020年期末考试卷A xff08 参考答案见底部 xff09 1 软件需求分析阶段的工作 xff0c 可以分为以下4个方面 xff1a 对问题的识别 分析与综合 编写需求分析文档以及 xff08 xff09
  • C#自定义控件

    一 开发环境和工具 1 WIN10系统 2 Visual Studio社区版 2019 xff08 C xff09 二 创建自定义控件窗体 添加一个自定义控件 xff0c 右键解决方案 xff0c 点击添加 xff0c 然后点击用户控件 选
  • vdo 虚拟数据优化器详解以及配置

    VDO 我的博客 xff1a https blog itwk cc vdo xff08 虚拟数据优化器 xff09 是一个内核模块 xff0c 目的是通过重删 xff08 重复数据删除 xff09 减少磁盘的的空间占用 xff0c 以及减少
  • ROS 自定义消息类型方法

    流程 1 在package中新建文件夹名为msg 2 在msg文件夹中创建消息 xff08 此处以my msg msg xff09 为例 xff0c 注意的是要以msg为后缀名 内容举例如下 xff1a int32 data1 float6
  • 计算机网络第七版笔记--第一章

    第一章概述 1 1 计算机网络在信息时代中的作用 1 互联网是覆盖全球的 xff0c 具有两个重要基本特点 xff0c 即连通性和共享 1 2互联网的概述 1 2 1网络的网络 1 计算机网络 xff08 简称网络 xff09 由若干结点
  • 0.1+0.2不等于0.3 原因

    在计算机进行数字计算时会先将十进制转化为二进制进行计算 xff0c 由于二进制表示的有限数字不能超过 52 位在 JavaScript 里是不能精确存储的 xff0c 计算机进行了四舍五入这时造成了数字误差导致计算结果不为0 3 总结 xf
  • mac 终端 配置代理

    即使打开代理 xff0c mac终端默认不走 xff0c 需要配置 一 复制终端代理命令 export http proxy 61 http 127 0 0 1 1089 export https proxy 61 http 127 0 0
  • 【linux】安装Linux的交叉编译工具链

    1 linux中装软件的特点 linux中安装软件比windows中复杂 linux中安装软件一般有以下几种方法 xff1a 第一种 xff1a 在线安装 譬如ubuntu中使用apt get install vim来安装vim软件 第二种
  • 基于STM32F429 的 FreeRTOS 环境下 LCD1602驱动实现

    本文是基于STM32F429在FreeRTOS下的HAL库开发 xff0c 并验证在多任务不同优先级情况下运行情况 LCD1602介绍 xff1a 是一个只能显示字母 数字 符号的点阵型液晶模块 一行可以显示16个字符 xff0c 可以显示
  • 查询MYSQL和查询HBASE速度比较

    MySQL xff0c 关系型数据库 xff1b HBase xff0c NoSql数据库 查询Mysql和查询HBase xff0c 到底哪个速度快呢 xff1f 与一些真正的大牛讨论时 xff0c 他们说HBase写入速度 xff0c
  • Office Online Server 在线编辑Office文档,安装部署

    最近公司项目需求 xff0c 需要搭建一个office预览编辑的服务 xff0c 在网上找到了Office Online Server在线编辑office文档 xff0c 以下把自己搭建过程记录 一 Office Online Server
  • 安装vmware搭建k8s集群(亲试无坑)

    一 前言 下面这个坑我也遇到了 xff0c 同时看到别人的博客也遇到了 xff0c 害的我废了一天的时间来解决这个问题 xff0c 但是毫无卵用 xff0c 气的我快吐血 xff1a 问题 xff1a 因为k8s把版本的问题 xff0c 一
  • Kaniko构建镜像

    一 前言 最近公司重构devops相关的一系列平台 xff0c 对于流水线中用容器方式交付的产品越来越多 xff0c 为了更加安全的方式来构建容器镜像 xff0c 采用Kaniko构建 在了解如何用Kaniko构建镜像之前 xff0c 我们
  • Mysql批量插入对比(附github仓库demo)

    前言 本文记录个人使用MySQL插入大数据总结较实用的方案 xff0c 通过对常用插入大数据的4种方式进行测试 xff0c for循环单条拼接SQL批量插入saveBatch 循环 43 开启批处理模式 最近趁空闲之余 xff0c 在对My