深入浅出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,一经查实,立即删除!

相关文章

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

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

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

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

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

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

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进行管理。目前在使用 接口测试和服务端性能测试 工具…

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

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

【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的函数。这个错误通…

ROS系列rqt的安装以及使用方法介绍

目录 1. 安装 2. 部分工具的功能介绍及使用方法 1&#xff09;rqt_gui 2&#xff09;rqt_topic 3&#xff09;rqt_graph 4&#xff09;qt_plot 5&#xff09;rqt_service_caller 6&#xff09;rqt_bag 1. 安装 安装极其简单&#xff0c;不多介绍&#xff0c;直接上命令…

反向海淘代购系统中的API接口列表

API测试入口|代购系统演示 item_get 获得淘宝商品详情item_get_pro 获得淘宝商品详情高级版item_review 获得淘宝商品评论item_fee 获得淘宝商品快递费用item_password 获得淘口令真实urlitem_list_updown 批量获得淘宝商品上下架时间seller_info 获得淘宝店铺详情item_search…

CrossPrefetch: Accelerating I/O Prefetching for Modern Storage——论文泛读

ASPLOS 2024 Paper 论文阅读笔记整理 问题 目前计算设备和存储设备之间的性能差距仍然很大。因此&#xff0c;主内存缓存和缓冲区被广泛用于操作系统、用户级文件系统[32]和I/O运行时&#xff0c;在隐藏性能差距和减少I/O瓶颈方面发挥关键作用[23&#xff0c;26&#xff0c;3…

python运算符和表达式

目录 算数运算符 赋值运算符 关系运算符 逻辑运算符 位运算符 成员运算符 运算符优先级 易错点&#xff1a; 算数运算符 赋值运算符 关系运算符 int可以转换成float 逻辑运算符 可以是一个运算也可以是一个字符串 左边为空格&#xff0c;为假&#xff0c;输出为空 优…

MySQL中获取时间的方法

大家好&#xff0c;在MySQL数据库开发中&#xff0c;获取时间是一个常见的需求。MySQL提供了多种方法来获取当前日期、时间和时间戳&#xff0c;并且可以对时间进行格式化、计算和转换。 以下是一些常用的MySQL时间函数及其示例&#xff1a; 1、NOW()&#xff1a;用于获取当前…

Mysql:通过一张表里的父子级,递归查询并且分组分级

表&#xff1a;gc_jzst_single_base 需求&#xff1a;要求返回这张表里符合条件的数据&#xff0c;且有父子级关系的&#xff0c;展示为同一组且分级&#xff0c;给后续业务调用 代码 WITH RECURSIVE t1 AS (SELECTsingle_id,old_build_single_id,single_name,bulid_code,1 A…

Mybatis Map接收数据tinyint(1)类型错误

Mybatis Map接收数据tinyint 1 类型错误 问题描述数据库字段Mybatis查询语句问题处理方案一方案二方案三 问题描述 Mybatis开发过程中&#xff0c;使用Map接收返回数据时发现tinyint(1)类型字段自动转换成了Boolean类型&#xff0c;导致查询的数据出现问题 数据库字段 数据库…

实验四、零比特插入《计算机网络》

但凡这句话有一点用的话也不至于一点用都没有。 目录 一、实验目的 二、实验内容 三、实验小结 一、实验目的 掌握零比特插入原理及方法使用任意编程语言实现零比特插入方法。 二、实验内容 掌握零比特插入原理及方法 点对点协议 PPP&#xff08;Point-to-Point Protoco…

Elasticsearch:基于多个 kNN 字段对文档进行评分

作者&#xff1a;来自 Elastic Madhusudhan Konda 通过具有多个 kNN 字段的最接近的文档对文档进行评分 Elasticsearch 不仅仅是一个词法&#xff08;文本&#xff09;搜索引擎。 Elasticsearch 是多功能搜索引擎&#xff0c;除了传统的文本匹配之外&#xff0c;还支持 k 最近…