MySQL 大量数据插入优化

效率最好的方式是:批量插入 + 开启事务。

1、数据批量插入相比数据逐条插入的运行效率得到极大提升;

## 批量插入
INSERT INTO `table` (`field1`, `field12`,...) VALUES ('valuea1', 'valuea2',...), ('valueb1', 'valueb2',...),...;

当数据逐条插入时,每条插入操作都需要进行一次数据库连接和一次磁盘写入操作,这会导致频繁的网络通信和磁盘 I/O 开销。如果有大量的数据需要插入,这些额外的开销会导致插入速度变慢,降低整体的运行效率。

相比之下,批量插入将多条数据合并为一个批次进行插入。通过一次数据库连接和一次磁盘写入操作,可以将多条数据一次性插入到数据库中。这样可以减少网络通信次数和磁盘 I/O 操作次数,大大提高了数据插入的效率。

批量插入的效率提升主要有以下几个方面的原因:

  1. 减少网络通信开销:批量插入可以通过一次数据库连接和一次传输操作将多条数据发送给数据库,减少了网络通信的次数和开销。
  2. 减少磁盘 I/O 操作:批量插入将多条数据合并为一个写入操作,减少了磁盘的读写次数,降低了磁盘 I/O 的开销。
  3. 优化事务管理:批量插入可以将多条插入操作合并为一个事务,减少了事务的开启和提交次数,提高了事务管理的效率。

2、数据逐条插入时,显示开启事务相比无事务的运行效率得到极大提升;

MySQL 每条插入操作,都会在内部建立一个隐式事务,在这个事务内进行真正的插入操作,所以逐条插入需要不停的创建事务和提交事务,造成较大的开销;显示开启事务,将多条插入操作放在同一个事务内,等都执行完再提交事务,可以减少创建和提交事务的次数,从而降低消耗。

## 没有开启事务
INSERT INTO `table` (`field1`, `field12`,...) VALUES ('value1', 'value2',...);
INSERT INTO `table` (`field1`, `field12`,...) VALUES ('value1', 'value2',...);## 开启事务
START TRANSACTION;
INSERT INTO `table` (`field1`, `field12`,...) VALUES ('value1', 'value2',...);
INSERT INTO `table` (`field1`, `field12`,...) VALUES ('value1', 'value2',...);
COMMIT;

当数据逐条插入时,使用事务可以显著提升运行效率。这是因为事务的特性可以减少磁盘 I/O 操作,从而减少数据库引擎与磁盘之间的交互次数,提高数据插入的性能。

在无事务的情况下,每次插入一条数据都会立即写入磁盘,这导致了频繁的磁盘 I/O 操作。每次写入磁盘都包括了寻址、数据传输和磁盘写入等操作,这些操作的开销很大,会显著降低数据插入的速度。

而在开启事务的情况下,可以将多条插入操作打包成一个事务,然后一次性提交到数据库。这样可以将多个插入操作合并为一个写入磁盘的过程,减少了磁盘 I/O 操作的次数。数据库引擎可以优化事务的提交过程,将数据缓存在内存中并批量写入磁盘,从而减少了磁盘访问的次数,提高了插入操作的效率。

因此,对于大量逐条插入数据的场景,使用事务可以极大地提升运行效率,减少磁盘 I/O 操作,加快数据的插入速度。

3、INSERT 操作涉及磁盘 I/O 操作的原因主要有两个方面

数据持久化:INSERT 操作的目的是将新的数据插入到数据库中,以保持数据的持久性。为了实现持久化,数据库引擎需要将插入的数据写入磁盘,将其保存在物理存储介质上(如硬盘或固态硬盘)。这涉及到将数据从内存中的缓冲区或日志文件写入到磁盘的过程,即磁盘 I/O 操作。

索引更新:如果表中定义了索引,那么在执行 INSERT 操作时,数据库引擎还需要相应地更新索引数据结构。索引是用于提高数据库查询性能的数据结构,它们存储在磁盘上并与表的数据分开存储。当插入新的数据时,数据库引擎需要更新索引,以确保索引的正确性和查询的准确性。这也涉及到磁盘 I/O 操作。

4、在MySQL中,默认情况下,每个SQL语句都自动开启一个事务

在MySQL中,默认情况下,每个 SQL 语句被视为一个单独的事务,即每个 SQL 语句都会自动开启事务并在执行完成后立即提交。这种自动提交模式是MySQL的默认模式,也称为自动提交模式。当自动提交模式开启时,每个 SQL 语句都会被视为一个独立的事务,并且在执行后立即提交,使得更改立即持久化到数据库中。

自动提交模式可以通过设置来控制。默认情况下,MySQL 的自动提交模式是开启的,即每个 SQL 语句都自动成为一个事务。可以使用 SET AUTOCOMMIT=0 命令来关闭自动提交模式。如果要将多个 SQL 语句组合在一个显式的事务中执行,需要在组合语句之前显示使用START TRANSACTION或BEGIN语句,然后在所有语句都执行完毕后显示执行COMMIT或ROLLBACK语句提交或回滚事务。

当自动提交模式关闭时,需要手动控制事务的边界,并显式地进行事务的提交或回滚,以确保数据的一致性和原子性。

批量插入需要考虑限制 sql 语句的长度,不能超过 MySQL 对 SQL 语句的长度限制

max_allowed_packet 是一个MySQL服务器参数,用于控制单个网络数据包的最大大小。它指定了MySQL服务器接收或发送的最大数据包大小限制,以字节为单位。

该参数对于处理大型查询或传输大量数据非常重要。如果试图发送一个超过 max_allowed_packet 大小限制的数据包,MySQL服务器将会拒绝该数据包,并且可能会导致通信错误或截断数据。

使用 show VARIABLES like ‘%max_allowed_packet%’; 可以查看网络包大小限制:
在这里插入图片描述

使用事务可以提高数据的插入效率,但事务需要控制大小,事务太大可能也会影响执行的效率。

innodb_log_buffer_size 是用于配置 InnoDB 存储引擎的日志缓冲区大小的变量。它指定了用于存储事务日志的内存缓冲区的大小。

InnoDB 存储引擎使用事务日志(也称为 redo log)来确保事务的持久性和恢复能力。在事务提交之前,相关的修改操作被写入到日志缓冲区中,而不是直接写入到磁盘上的数据文件,然后再由后台线程将日志刷新到磁盘上的 InnoDB 日志文件中。这样可以提高事务的性能,因为写入内存比写入磁盘要快得多。

事务需要控制大小,若事务大小超过上限设置,Innodb 会把数据刷到磁盘中,这时会降低效率。

较大的缓冲区可以容纳更多的日志记录,从而减少了频繁的磁盘写入操作,提高了事务的性能。然而,如果设置过大,可能会占用过多的内存资源。需要在性能和内存消耗之间进行权衡,以获得最佳的事务处理性能。

事务日志被刷新到磁盘上的日志文件,并不代表该事务已经提交,只是为了确保事务的持久性和恢复能力。即使发生故障或异常情况,数据库系统也可以通过事务日志进行恢复和回滚操作。

事务的提交是一个独立的操作,它将会持久化事务对数据库的修改,并使这些修改对其他会话可见。如果在事务日志刷盘后没有执行提交操作,那么这个事务的修改将不会被持久化到数据文件中,也不会对其他会话可见。在数据库系统的崩溃或重启情况下,这个事务的修改将会被回滚或者丢失。

使用 show variables like ‘%innodb_log_buffer_size%’; 可以查看日志缓存大小:
在这里插入图片描述

5、批量插入的优势

MySQL插入动作,主要有连接,传输,执行,提交/回滚等的动作

  1. 网络传输空间,每个插入操作都需要发送一个独立的网络请求,在请求中包含数据的内容和相关的协议头信息。批量插入多条数据,减少了请求头部的重复发送和处理,从而节省了网络带宽和传输时间。
  2. 网络连接,批量插入使用一个连接,减少网络连接次数,从而减少连接建立和断开开销。
  3. 通过合并SQL语句,减少SQL语句解析的次数;合并后的 SQL 语句可以共享解析结果和执行计划,避免了重复的解析过程;合并的 SQL 语句也需要考虑查询的并发性、锁的粒度等因素,以避免潜在的并发冲突或性能问题。
  4. 事务方面,逐条插入每次都会新建一个事务,批量插入只会使用一个事务。批量插入可以减少事务的启动和提交次数,降低开销。
  5. 磁盘IO操作,合并插入可以减少事务日志的数量,降低事务日志的总量,减少了对磁盘的写入操作,降低日志刷盘的数据量和频率,从而提高效率。(对于插入操作而言,每次逐条插入都会生成一条日志记录,包括事务开始、插入语句执行和事务提交等信息)

mybatis-plus 的 saveBatch 方法源码分析

进入 mybatis-plus 的 saveBatch 方法,可以看到是由 ServiceImpl 实现的,进入核心方法:

    @Transactional(rollbackFor = {Exception.class})public boolean saveBatch(Collection<T> entityList, int batchSize) {String sqlStatement = this.getSqlStatement(SqlMethod.INSERT_ONE);return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> {sqlSession.insert(sqlStatement, entity);});}public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {Assert.isFalse(batchSize < 1, "batchSize must not be less than one", new Object[0]);return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, (sqlSession) -> {int size = list.size();int i = 1;for(Iterator var6 = list.iterator(); var6.hasNext(); ++i) {E element = var6.next();consumer.accept(sqlSession, element);if (i % batchSize == 0 || i == size) {sqlSession.flushStatements();}}});}

分析这段代码,executeBatch 方法种的 consumer.accept(sqlSession, element) 执行的就是 saveBatch 的 sqlSession.insert(sqlStatement, entity),可以看到确实是 for 循环一条一条执行 insert 操作。在 executeBatch 使用了 @Transactional 开启了事务,在循环插入后再提交事务。

mybatis plus 使用了开启事务的方式提升插入效率,是否还会使用批量插入来提升效率。继续点进代码看,一直到 MySQL 驱动(mysql-connector-java:8)

   protected long[] executeBatchInternal() throws SQLException {synchronized(this.checkClosed().getConnectionMutex()) {if (this.connection.isReadOnly()) {throw new SQLException(Messages.getString("PreparedStatement.25") + Messages.getString("PreparedStatement.26"), "S1009");} else if (this.query.getBatchedArgs() != null && this.query.getBatchedArgs().size() != 0) {int batchTimeout = this.getTimeoutInMillis();this.setTimeoutInMillis(0);this.resetCancelledState();try {this.statementBegins();this.clearWarnings();long[] var3;if (!this.batchHasPlainStatements && (Boolean)this.rewriteBatchedStatements.getValue()) {// 启用 rewriteBatchedStatements = true,使用多值语句进行重写,拼接 sql 批量插入数据。// INSERT INTO `table` (`field1`, `field12`,...) VALUES ('valuea1', 'valuea2',...), ('valueb1', 'valueb2',...),...; 方式;if (this.getQueryInfo().isRewritableWithMultiValuesClause()) {var3 = this.executeBatchWithMultiValuesClause(batchTimeout);return var3;}// 如果批处理中包含多个非简单语句,并且批量参数个数大于3,则使用该方法执行批处理。// INSERT INTO `table` (`field1`, `field12`,...) VALUES ('value1', 'value2',...);// UPDATE my_table SET field1= ?, field12= ?, field13= ?, ... WHERE field14= ?";if (!this.batchHasPlainStatements && this.query.getBatchedArgs() != null && this.query.getBatchedArgs().size() > 3) {var3 = this.executePreparedBatchAsMultiStatement(batchTimeout);return var3;}}// 否则,使用该方法按顺序执行处理每条sql语句。简单语句或参数个数不超过3个。var3 = this.executeBatchSerially(batchTimeout);return var3;} finally {this.query.getStatementExecuting().set(false);this.clearBatch();}} else {return new long[0];}}}

需要在 MySQL 的 jdbcUrl 中设置 rewriteBatchedStatements = true:

jdbc:mysql://localhost:3306?rewriteBatchedStatements=true

executeBatchWithMultiValuesClause(batchTimeout) 方法:

  1. 该方法用于执行批处理操作,并且支持使用多值语句进行批量插入。
  2. 如果查询可以使用多值语句进行重写,且启用了 rewriteBatchedStatements,则会选择该方法来执行批处理。
  3. 多值语句是将多个值组合在一条 SQL 语句中,用于一次性插入多个记录,可以提高插入性能。

executePreparedBatchAsMultiStatement(batchTimeout) 方法:

  1. 该方法用于执行包含多个非简单语句的批处理操作。
  2. 如果批处理中的参数个数大于 3,且满足其他条件,该方法会被选择来执行批处理。

executeBatchSerially(batchTimeout) 方法:

  1. 该方法用于按顺序逐个执行批处理中的每个语句。
  2. 该方法通常在批处理中只包含简单语句(没有参数)或参数个数较少的情况下使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/11617.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++类细节,反汇编,面试题02

文章目录 2. 虚函数vs纯虚函数3. 重写vs重载vs隐藏3.1. 为什么C可以重载&#xff1f; 4. struct vs union4.1. 为什么要内存对齐&#xff1f; 5. static作用6. 空类vs空结构体6.1. 八个默认函数&#xff1a;6.2. 为什么空类占用1字节 7. const作用7.1 指针常量vs常量指针vs常量…

【SRC-CPP-OpenCV】给图片更换背景色

文章目录 Part.I IntroductionPart.II Main_bodyChap.I 源码简析Chap.II 效果展示 Part.III 源码Reference Part.I Introduction 本文将介绍如何用 OpenCV 更换图片的背景色&#xff08;附有完整代码&#xff09;。 Part.II Main_body Chap.I 源码简析 配置部分&#xff1a…

1-3ARM_GD32点亮LED灯

简介&#xff1a; 最多可支持 112 个通用 I/O 引脚(GPIO)&#xff0c;分别为 PA0 ~ PA15&#xff0c;PB0 ~ PB15&#xff0c;PC0 ~ PC15&#xff0c;PD0 ~ PD15&#xff0c;PE0 ~ PE15&#xff0c;PF0 ~ PF15 和 PG0 ~ PG15&#xff0c;各片上设备用其来实现逻辑输入/输出功能。…

【论文精读】| KBS2023-TMBL-多模态情感分析系列文章解读

TMBL: Transformer-based multimodal binding learning model for multimodal sentiment analysis 一. KBS2023-TMBL-用于多模态情感分析的极向量和强度向量混合器模型1 Abstract1.1 Motivation1.2 Method1.3 Results 2. Related Work2.1 情感分析2.1 基于transformer的2.1 模态…

LeetCode/NowCoder-链表经典算法OJ练习2

最好的&#xff0c;不一定是最合适的&#xff1b;最合适的&#xff0c;才是真正最好的。&#x1f493;&#x1f493;&#x1f493; 目录 说在前面 题目一&#xff1a;分割链表 题目二&#xff1a;环形链表的约瑟夫问题 SUMUP结尾 说在前面 dear朋友们大家好&#xff01;&…

(done) 什么是马尔可夫链?Markov Chain

参考视频&#xff1a;https://www.bilibili.com/video/BV1ko4y1P7Zv/?spm_id_from333.337.search-card.all.click&vd_source7a1a0bc74158c6993c7355c5490fc600 如下图所示&#xff0c;马尔可夫链条实际上就是 “状态机”&#xff0c;只不过状态机里不同状态之间的边上是 “…

车载电子电器架构 —— Vector对于车载以太网的解决方案(协议栈)

车载电子电器架构 —— Vector对于车载以太网的解决方案(协议栈) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你…

实战WinRAR捆绑图片和恶意程序并自动上线Cobalt Strike(cs钓鱼日记)

钓鱼 - WinRAR捆绑图片和恶意程序并自动上线Cobalt Strike 环境准备 工具&#xff1a;Cobalt Strike、Winrar压缩工具、一张JPG图片 虚拟机IP&#xff1a; 【攻击机】Kali&#xff1a;192.168.232.128 【靶机】win7&#xff1a;192.168.232.144 情景&#xff1a;在钓鱼事…

老黄终于不穿皮衣了,分享一个AI换装AI试衣软件!

用AI实现在线试衣&#xff0c;或者在线换装&#xff0c;这不是一个新概念&#xff0c;肯定有人这么想过&#xff0c;但并不是所有人能都能轻松做到啊&#xff01; 今天就来分享一个人人都可以实现的方法&#xff0c;而且是那种傻瓜式的不用付钱的那种&#xff0c;甚至可以把软件…

大数据在IT行业的应用与发展趋势及IT行业的现状与未来

大数据在IT行业中的应用、发展趋势及IT行业的现状与未来 一、引言 随着科技的飞速发展&#xff0c;大数据已经成为IT行业的重要驱动力。从数据收集、存储、处理到分析&#xff0c;大数据技术为各行各业带来了深远的影响。本文将详细探讨大数据在IT行业中的应用、发展趋势&#…

详解依赖注入的三种方法以及遇到问题的解决

各位大佬光临寒舍&#xff0c;希望各位能赏脸给个三连&#xff0c;谢谢各位大佬了&#xff01;&#xff01;&#xff01; 目录 1.三种依赖注入的方法 1.属性注入 优点 缺点 2.构造方法注入 优点 缺点 3.Setter注入 优点 缺点 4.小结 2.依赖注入常见问题的解决 1…

linux Nginx安装与启动

一、先到官网下载Nginx 官网地址&#xff1a; http://nginx.org/en/download.html 我下载的是nginx-1.20.2 二、下载好的文件上传到服务器&#xff0c;然后解压 1、上传到指定的服务器地址&#xff0c;我这里是公司服务器&#xff0c;目录都是定义好的&#xff0c;自己玩建…

本来还挺喜欢……

前阵子买了个天空星开发板&#xff0c;到手之后发觉不对劲。 之前我们玩玩开发板都是用的面包板的&#xff0c;就算是ESP那种比较宽的板子用两个面包板拼一下也勉强可以用。 但是天空星它的引脚是分为两组&#xff0c;每组有两排&#xff0c;如果我们还是直接使用面包板的话&a…

单页源码加密屋zip文件加密API源码

简介&#xff1a; 单页源码加密屋zip文件加密API源码 api源码里面的参数已改好&#xff0c;往服务器或主机一丢就行&#xff0c;出现不能加密了就是加密次数达到上限了&#xff0c;告诉我在到后台修改加密次数 点击下载

【文献阅读】企业ESG表现与创新——来自A股上市公司的证据

企业ESG表现与创新——来自A股上市公司的证据 1.引言 第一段——背景介绍 可持续发展 碳达峰、碳中和 ESG既是从微观层面解决全球性社会问题的必要&#xff0c;也是实现我国经济转型、促进高质量发展的有效手段。 2017.12证监会&#xff1a;重点排污企业的环境披露 2021.6证监…

【ARM Cortex-M 系列 2.1 -- Cortex-M7 Debug system registers】

请阅读【嵌入式开发学习必备专栏】 文章目录 Debug system registers中断控制状态寄存器&#xff08;ICSR&#xff09;Debug Halting Control and Status Register, DHCSR Debug 寄存器DCRSR与DCRDRCPU 寄存器读操作CPU 寄存器写操作CPU 寄存器选择CPU 寄存器读写示例 调试故障…

第十五篇:全面防护:构建不容侵犯的数据库安全策略与实战指南

全面防护&#xff1a;构建不容侵犯的数据库安全策略与实战指南 1. 引言&#xff1a;数据库安全的现代战略 1.1 简介&#xff1a;数据库安全在当今的数字化时代中的重要性 在数字化的浪潮中&#xff0c;数据已成为企业乃至国家的核心资产&#xff0c;其价值不亚于实体世界的黄…

第五百零三回

文章目录 1. 概念介绍2. 使用方法2.1 普通路由2.2 命名路由 3. 示例代码4. 内容总结 我们在上一章回中介绍了"使用get显示Dialog"相关的内容&#xff0c;本章回中将介绍使用get进行路由管理.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…

RAG应用中的路由模式

依据的用户查询意图在 RAG 应用程序使用“路由控制模式”可以帮助我们创建更强大的 RAG 应用程序。我们通常希望用户能够访问的数据可以来自各种来源,如报告、文档、图片、数据库和第三方系统。 对于基于业务的 RAG 应用程序,我们可能还希望用户能够与其它业务系统进行交互,…

大模型微调方法汇总

微调方法 Freeze方法P-tuning方法 prefix-tuningPrompt TuningP-tuning v1P-tuning v2Lora方法 重要相关参数LoRA 的优势Qlora方法 相关参数微调经验 模型选择模型大小选择数据处理微调方案英文模型需要做词表扩充吗&#xff1f;如何避免灾难遗忘大模型的幻觉问题微调后的输出…