深入浅出mysql海量数据批量更新插入、批量查询

1. mysql的批量写

mysql 批量插入可以用下面这种,在values 之后跟上各种多个值列表。但这种写法可能导致sql长度超长、锁超时等问题。

insert into (`field1`,`field1`,`field1`,) values (value01,value02,value03),(value11,value12,value13),(value21,value22,value23) .....;

在数据量较大的时候,上面这种方式就不太合适。mysql提供了批量写入的方法,将大批量的sql脚本一批次发送到服务端,减少IO次数,然后统一一次执行sql。这种写入效率会高很多。如下所示,先执行statement.addBatch()先将sql添加到statement列表,然后执行statement.executeBatch()统一批量执行sql。mybatis-plus的批量提交的底层实现就是基于此,它默认将1000条sql作为一个批次。

      Class.forName("com.mysql.cj.jdbc.Driver");// 创建连接conn = DriverManager.getConnection(url, user, password);// 创建预编译 sql 对象statement = conn.prepareStatement("UPDATE sku_inventory set stock =stock+1  where id = ?");long a = System.currentTimeMillis(); // 计时// 这里添加 100 个批处理参数for (int i = 1; i <= 10000; i++) {statement.setInt(1, i);statement.addBatch(); // 批量添加}long b = System.currentTimeMillis(); // 计时System.out.println("添加参数耗时:" + (b-a)); // 计时int[] r = statement.executeBatch(); // 批量提交statement.clearBatch(); // 清空批量添加的 sql 命令列表缓存

理论上,上面的sql是批量提交到mysql server统一执行的,但在默认情况下实际上它还是一条条执行命令,要真正的批量执行sql,需要在jdbc连接url加上rewriteBatchedStatements=true,这个参数的默认只是false
在这里插入图片描述
从wireshark抓包的情况来看,在默认配置下,sql批量执行貌似没起作用。这里客户端发送一个sql脚本然后得到一个response响应,发送一个sql得到一个响应,循环万福,就是在串行化执行sql。
在这里插入图片描述
下面是添加了rewriteBatchedStatements=true这个参数后的抓包截图,jdbc客户端重写了sql语句,它把多个sql语句用分号分隔连接在一起,形成一个大sql脚本, 然后将这个sql脚本一次性发送到server端,最后接收到了大量的response响应。这个才是我们想要的接口
在这里插入图片描述
rewriteBatchedStatements这个参数不只是对插入数据有效,对update delete语句也有同样的效果。

另外如果有更大批量的结构化数据需要插入,可以使用 load data local infile这个指令,这个指令可以将文本文件中的数据快速导入到mysql,这个指令比普通的语句快20倍以上。本地测试在没有激烈的锁竞争情况下插入100万数据只用了10秒钟,当然在真实环境中要考虑文本文件传输的I/O耗时,这会增加更多的耗时。
这个指令一般和replace into insert into 结合起来使用。

        load data local infile {fileName} -- 文本文件名replace into table sku_inventory  -- 表名CHARACTER SET utf8mb4 -- 文本文件的字符集编码COLUMNS TERMINATED by ',' -- 文本文件的字段分隔符IGNORE 1 lines -- 忽略一行,从第二行读数据因为我的csv文件第一行是字段名(`id`, stock,spu_id,`name`)

这个指令需要指定数据文件名、 字符集编码、文本文件的字段分隔符,数据库的字段名列表(注意和文本文件中字段列的顺序一致)
注意:要使用这功能需要先在服务端将环境变量 local_infileon,表示启用这个特性。另外之外还要在客户端启动这个功能,在jdbc连接url上加上参数allowLoadLocalInfile=true

在这里插入图片描述

2. 批量读

大数据的查询需要渐进式查询,如果用普通的查询可能导致mysql数据报文太大、JVM内存溢出等问题。
mysql上有两种解决方案,(1) 游标查询;(2)流式查询。
国内一般都用mybatis做orm框架,现在用mybatis实现这两种功能。
mybatis提供了org.apache.ibatis.cursor.Cursor进行游标查询,但这本质上还是客户端的游标查询,实际上还是一次性从mysql服务器检索出所有数据。不信,请往下看。

1) 游标查询

在这里插入图片描述

<select id="fetchAll" fetchSize="10000" resultMap="BaseResultMap">SELECT <include refid="Base_Column_List" />FROM sku_inventory WHERE  id > #{gtId}</select>

从上面可以看到我定义了一个游标结果集类型的接口,且定义了fetchSize,
但是从com.mysql.cj.protocol.a.BinaryResultsetReader#read方法可以看到,客户端一次性获取到了所有的数据,它是一个静态结果集,并没有分段渐进获取。

在这里插入图片描述

现在我在连接参数上加上useCursorFetch=true,重启项目再执行接口。再看看debug时截图信息,现在结果集是游标类型结果集ResultsetRowsCursor。而且从wirekshar抓包来看,还出现了Fetch Data这个数据报文,这个数据报文内容是10000,这恰好和xml中配置的fetchSize="10000"对应上了。在之前的那个示例中,没加useCursorFetch连接参数,jdbc客户端是没有Fetch Data数据报文的。

2)流式查询

流式查询也可以用org.apache.ibatis.cursor.Cursor实现,只需要将fetchSize设为-2147483648即可启用。为啥是-2147483648尼,因为这个值是Integer的最小值Integer.MIN_VALUE。mysql驱动判断是否是流式查询的方法在com.mysql.cj.jdbc.StatementImpl#createStreamingResultSet中,它的判断逻辑是:
结果集类型是FORWARD_ONLY 、结果集并发类型是CONCUR_READ_ONLYfetchSizeInteger.MIN_VALUE 就启用流式结果集。其中ResultType默认是FORWARD_ONLYresultSetConcurrency默认是CONCUR_READ_ONLY,所以我们只要保证fetchSizeInteger.MIN_VALUE ,那么就可以启用流式结果集。
在这里插入图片描述

mybatis xml中修改下fetchSize参数,其他的不用变更(这里得先把参数useCursorFetch恢复成默认值false)

    <select id="fetchAll" fetchSize="-2147483648" resultMap="BaseResultMap">SELECT <include refid="Base_Column_List" />FROM sku_inventory WHERE  id > #{gtId}</select>

从下面的截图可以看出,此时返回结构是流式结果集ResultsetRowsStreaming

在这里插入图片描述

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

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

相关文章

力扣1493.删掉一个元素以后全为1

力扣1493.删掉一个元素以后全为1 单调队列&#xff1a;找到一个最多1个0的子数组 最终结果为该子数组长度-1 特判如果数组全0&#xff0c;return 0 class Solution {public:int longestSubarray(vector<int>& nums) {int res0,sum0;for(int i0,j0;i<nums.size(…

Kotlin 异常处理

文章目录 什么是异常抛出异常通过异常信息解决异常捕获异常 什么是异常 我们在运行程序时&#xff0c;如果代码出现了语法问题或逻辑问题&#xff0c;会导致程序编译失败或退出&#xff0c;称为异常。运行结果会给出一个一长串的红色字&#xff0c;通常会给出异常信息&#xf…

使用springboot+vue实现阿里云oss上传

一、前言 我们后端开发中&#xff0c;时常需要用到文件上传的功能&#xff0c;无非是保存到服务器本地或者如阿里云、七牛云这种云存储的方案。本篇介绍一种使用后台springboot结合前端vue实现阿里云oss上传的功能。 二、实现过程 前端实现一个通用的上传组件UploadFile &l…

可以通过其瞳孔判断AI生成的人脸数据是否可靠

概述 我们都知道&#xff0c;GANs的发展使得生成相互之间无法区分的人脸图像成为可能。虽然这项技术在发展&#xff0c;但也有弊端&#xff0c;比如出现了用生成的人脸作为资料图片的虚假社交媒体账户。因此&#xff0c;随着GANs的发展&#xff0c;使用深度学习模型检测生成的…

python中有时使用pip安装库而有时又使用conda安装库,到底应该使用哪个管理工具进行库的安装呀?

决定使用conda还是pip来安装Python库主要基于以下几个因素&#xff1a; 库的可用性&#xff1a; Conda&#xff1a;如果你要安装的库在Anaconda的默认频道或conda-forge等其他Conda频道中存在&#xff0c;优先使用conda install。Conda不仅管理Python包&#xff0c;还能管理非…

Java Web学习笔记5——基础标签和样式

<!DOCTYPE html> html有很多版本&#xff0c;那我们应该告诉用户和浏览器我们现在使用的是HMTL哪个版本。 声明为HTML5文档。 字符集&#xff1a; UTF-8&#xff1a;现在最常用的字符编码方式。 GB2312&#xff1a;简体中文 BIG5&#xff1a;繁体中文、港澳台等方式…

Ubuntu的基本使用(ROS)

Ubuntu的基本使用&#xff08;ROS&#xff09; 终端常用指令 1. ls - 列出目录内容 用途&#xff1a;显示当前目录下的文件和文件夹。示例&#xff1a; ls&#xff1a;列出当前目录下的所有文件和文件夹。ls -l&#xff1a;以列表形式显示更详细的信息&#xff08;如权限、所…

ARM32开发——串口输出

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 需求串口数据发送串口打印实现复用功能串口发送流程&#xff08;了解&#xff09;串口的标志位关心的内容 需求 串口循环输出内容到…

大数据基础问题:在Hive中如何实现全增量统一的UDTF、内置函数、聚合、Join等计算引擎常见算子?

仁者见仁智者见智&#xff0c;每个程序员的方法都不一样&#xff0c;老的程序员和新的程序员之间的思维差距很大&#xff0c;新入公司的和老员工的代码差距也很大。 在Apache Hive中&#xff0c;实现全增量统一的用户定义表生成函数&#xff08;UDTF&#xff09;、内置函数、聚…

pdf文件怎么合并成一个文件

在现代办公环境中&#xff0c;PDF文件的使用已变得非常普遍。它们具有跨平台、易读性强的特点&#xff0c;因此被广泛应用于各种场合。然而&#xff0c;当需要处理大量的PDF文件时&#xff0c;如何有效地将它们合并成一个文件&#xff0c;成为了一个需要解决的问题。本文将详细…

【越界写null字节】ACTF2023 easy-netlink

前言 最近在矩阵杯遇到了一道 generic netlink 相关的内核题&#xff0c;然后就简单学习了一下 generic netlink 相关概念&#xff0c;然后又找了一到与 generic netlink 相关的题目。简单来说 generic netlink 相关的题目仅仅是将用户态与内核态的交互方式从传统的 ioctl 变成…

盘点学习Python常犯一些错误,你中了几个

对于刚入门的 Pythonista 在学习过程中运行代码是或多或少会遇到一些错误&#xff0c;刚开始可能看起来比较费劲。随着代码量的积累&#xff0c;熟能生巧当遇到一些运行时错误时能够很快的定位问题原题。下面整理了一些常见的 17 个错误&#xff0c;等你写出的代码不怎么出现这…

测试工具链

缺陷管理 bug管理工具 devops---项目管理--缺陷管理 bug管理地址 https://devsecops.mychery.com:8443/chery/project?filterROLE&statusACTIVE bug管理环境 采用公司的devops平台&#xff0c;对每个项目的bug进行管理。目前在使用 接口测试和服务端性能测试 工具…

HBase数据库面试知识点:第一部分 - 基础概念与特点(持续更新中)

目录 一、HBase基础概念 1. HBase定义 2. 核心组件 3. HBase的特点 二、HBase与传统RDBMS的区别 1. 数据类型 2. 数据操作 3. 存储方式 4. 伸缩性 5. 事务性 三、HBase数据模型 四、HBase的特点 五、HBase与Hadoop生态系统的关系 一、HBase基础概念 1. HBase定义 …

C++对CSV文件进行读,写,追加操作

1.读取CSV文件 // 读取csv文件 void read_csv(const std::string& file_path) {std::cout<<"文件路径: "<< file_path<<"\n";std::ifstream csv_data(file_path, std::ios::in);std::string line;if (!csv_data.is_open()) {std::c…

斯坦福抄袭清华、面壁智能大模型,当事人已道歉、删项目

6月4日&#xff0c;两名斯坦福大学生Aksh Garg和Siddharth Sharma&#xff0c;承认抄袭清华和面壁智能联合开发的MiniCPM-Llama3-V2.5&#xff08;以下简称V2.5&#xff09;多模态大模型事件&#xff0c;并在社交平台公开道歉、删掉开源项目。 该抄袭事件也得到了斯坦福大学AI…

阿里云计算之linux入门命令学习笔记(二)

Linux 提供了丰富的命令行工具&#xff0c;用于系统管理、文件操作、网络管理、进程控制等。以下是一些常用的 Linux 命令及其简要说明&#xff1a; 切换用户 su 命令 su (substitute user) 命令用于切换用户。 su - username # 切换到指定用户&#xff0c;并加载…

【python】成功解决“ImportError: cannot import name ‘triu’ from ‘scipy.linalg’”错误的全面指南

成功解决“ImportError: cannot import name ‘triu’ from ‘scipy.linalg’”错误的全面指南 在Python编程中&#xff0c;尤其是在使用scipy这个科学计算库时&#xff0c;可能会遇到ImportError错误&#xff0c;提示无法从scipy.linalg模块中导入名为triu的函数。这个错误通…

程序员职业生涯中的重要职业素养

程序员应该有什么职业素养&#xff1f; 作为一名程序员&#xff0c;职业素养在日常工作中至关重要。这不仅关系到个人职业发展的成功&#xff0c;也影响团队的整体效率和项目的成功。以下是几项对程序员而言尤为重要的职业素养&#xff1a; 1. 技术能力与学习能力 持续学习&…

浏览器原理---进程与线程

1、进程与线程的概念 从本质上说&#xff0c;进程和线程都是 CPU 工作时间片的一个描述&#xff1a; 进程描述了 CPU 在运行指令及加载和保存上下文所需的时间&#xff0c;放在应用上来说就代表了一个程序。线程是进程中的更小单位&#xff0c;描述了执行一段指令所需的时间。…