MySQL中的流式查询及游标查询方式(总结分享)

本篇文章给大家带来了关于mysql的相关知识,主要介绍了mysql中的流式查询及游标查询方式,具有很好的参考价值,希望对大家有所帮助。

MySQL中的流式查询及游标查询方式(总结分享)

推荐学习:mysql视频教程

一、业务场景

现在业务系统需要从 MySQL 数据库里读取 500w 数据行进行处理

迁移数据导出数据批量处理数据

二、罗列一下三种处理方式

常规查询:一次性读取 500w 数据到 JVM 内存中,或者分页读取流式查询:每次读取一条加载到 JVM 内存进行业务处理游标查询:和流式一样,通过 fetchSize 参数,控制一次读取多少条数据

2.1 常规查询

默认情况下,完整的检索结果集会将其存储在内存中。在大多数情况下,这是最有效的操作方式,更易于实现。

假设单表 500w 数据量,没有人会一次性加载到内存中,一般会采用分页的方式。

在这里,测试demo中只是为了监控JVM,所以没有采用分页,一次性将数据载入内存中

@Testpublic void generalQuery() throws Exception {    // 1核2G:查询一百条记录:47ms    // 1核2G:查询一千条记录:2050 ms    // 1核2G:查询一万条记录:26589 ms    // 1核2G:查询五万条记录:135966 ms    String sql = "select * from wh_b_inventory limit 10000";    ps = conn.prepareStatement(sql);    ResultSet rs = ps.executeQuery(sql);    int count = 0;    while (rs.next()) {        count++;    }    System.out.println(count);}

JVM监控

我们将对内存调小-Xms70m -Xmx70m

整个查询过程中,堆内存占用逐步增长,并且最终导致OOM:

java.lang.OutOfMemoryError: GC overhead limit exceeded

1、频繁触发GC

2、存在OOM隐患

MySQL中的流式查询及游标查询方式(总结分享)

2.2 流式查询

流式查询有一点需要注意:必须先读取(或关闭)结果集中的所有行,然后才能对连接发出任何其他查询,否则将引发异常,其 查询会独占连接。

从测试结果来看,流式查询并没有提升查询的速度

@Testpublic void streamQuery() throws Exception {    // 1核2G:查询一百条记录:138ms    // 1核2G:查询一千条记录:2304 ms    // 1核2G:查询一万条记录:26536 ms    // 1核2G:查询五万条记录:135931 ms    String sql = "select * from wh_b_inventory limit 50000";    statement = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);    statement.setFetchSize(Integer.MIN_VALUE);    ResultSet rs = statement.executeQuery(sql);    int count = 0;    while (rs.next()) {        count++;    }    System.out.println(count);}

JVM监控

我们将堆内存调小-Xms70m -Xmx70m

我们发现即使堆内存只有70m,却依然没有发生OOM

MySQL中的流式查询及游标查询方式(总结分享)

2.3 游标查询

注意:

1、需要在数据库连接信息里拼接参数 useCursorFetch=true

2、其次设置 Statement 每次读取数据数量,比如一次读取 1000

从测试结果来看,游标查询在一定程度缩短了查询速度

@Testpublic void cursorQuery() throws Exception {    Class.forName("com.mysql.jdbc.Driver");    // 注意这里需要拼接参数,否则就是普通查询    conn = DriverManager.getConnection("jdbc:mysql://101.34.50.82:3306/mysql-demo?useCursorFetch=true", "root", "123456");    start = System.currentTimeMillis();      // 1核2G:查询一百条记录:52 ms     // 1核2G:查询一千条记录:1095 ms    // 1核2G:查询一万条记录:17432 ms    // 1核2G:查询五万条记录:90244 ms    String sql = "select * from wh_b_inventory limit 50000";    ((JDBC4Connection) conn).setUseCursorFetch(true);    statement = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);    statement.setFetchSize(1000);    ResultSet rs = statement.executeQuery(sql);    int count = 0;    while (rs.next()) {        count++;    }    System.out.println(count);}

JVM监控

我们将堆内存调小-Xms70m -Xmx70m

我们发现在单线程情况下,游标查询和流式查询一样,都能很好的规避OOM,并且游标查询能够优化查询速度。

MySQL中的流式查询及游标查询方式(总结分享)

三、RowData

ResultSet.next() 的逻辑是实现类 ResultSetImpl 每次都从 RowData 获取下一行的数据。RowData 是一个接口,实现关系图如下

蓝心千询 蓝心千询

蓝心千询是vivo推出的一个多功能AI智能助手

蓝心千询 34 查看详情 蓝心千询

MySQL中的流式查询及游标查询方式(总结分享)

3.1 RowDataStatic

默认情况下 ResultSet 会使用 RowDataStatic 实例,在生成 RowDataStatic 对象时就会把 ResultSet 中所有记录读到内存里,之后通过 next() 再一条条从内存中读

3.2 RowDataDynamic

当采用流式处理时,ResultSet 使用的是 RowDataDynamic 对象,而这个对象 next() 每次调用都会发起 IO 读取单行数据

3.3 RowDataCursor

RowDataCursor 的调用为批处理,然后进行内部缓存,流程如下:

首先会查看自己内部缓冲区是否有数据没有返回,如果有则返回下一行如果都读取完毕,向 MySQL Server 触发一个新的请求读取 fetchSize 数量结果并将返回结果缓冲到内部缓冲区,然后返回第一行数据

总结来说就是:

默认的 RowDataStatic 读取全部数据到客户端内存中,也就是我们的 JVM;

RowDataDynamic 每次 IO 调用读取一条数据;

RowDataCursor 一次读取 fetchSize 行,消费完成再发起请求调用。

四、JDBC 通信原理

在 JDBC 与 MySQL 服务端的交互是通过 Socket 完成的,对应到网络编程,可以把 MySQL 当作一个 SocketServer,因此一个完整的请求链路应该是:

JDBC 客户端 -> 客户端 Socket -> MySQL -> 检索数据返回 -> MySQL 内核 Socket Buffer -> 网络 -> 客户端 Socket Buffer -> JDBC 客户端

4.1 generalQuery 普通查询

普通查询会将当次查询到的所有数据加载到JVM,然后再进行处理。

如果查询数据量过大,会不断经历 GC,然后就是内存溢出

4.2 streamQuery 流式查询

服务端准备好从第一条数据开始返回时,向缓冲区怼入数据,这些数据通过TCP链路,怼入客户端机器的内核缓冲区,JDBC会的inputStream.read()方法会被唤醒去读取数据,唯一的区别是开启了stream读取的时候,每次只是从内核中读取一个package大小的数据,只是返回一行数据,如果1个package无法组装1行数据,会再读1个package。

4.3 cursorQuery 游标查询

当开启游标的时候,服务端返回数据的时候,就会按照fetchSize的大小返回数据了,而客户端接收数据的时候每次都会把换缓冲区数据全部读取干净,假如数据有1亿数据,将FetchSize设置成1000的话,会进行10万次来回通信;

由于MySQL方不知道客户端什么时候将数据消费完,而自身的对应表可能会有DML写入操作,此时MySQL需要建立一个临时空间来存放需要拿走的数据。

因此对于当你启用useCursorFetch读取大表的时候会看到MySQL上的几个现象:

1.IOPS飙升2.磁盘空间飙升3.客户端JDBC发起SQL后,长时间等待SQL响应数据,这段时间就是服务端在准备数据4.在数据准备完成后,开始传输数据的阶段,网络响应开始飙升,IOPS由“读写”转变为“读取”。IOPS (Input/Output Per Second):磁盘每秒的读写次数5.CPU和内存会有一定比例的上升

五、并发场景

并发调用:Jmete 1 秒 10 个线程并发调用

流式查询内存性能报告如下

并发调用对于内存占用情况也很 OK,不存在叠加式增加

MySQL中的流式查询及游标查询方式(总结分享)

游标查询内存性能报告如下

MySQL中的流式查询及游标查询方式(总结分享)

六、总结

1、游标查询和流式查询在单线程下都能够规避OOM的情况;

2、在查询速度上游标查询比流式查询更快,流式查询和普通查询相比并不能缩短查询时间;

3、在并发场景下,流式查询堆内存走势更加稳定,不存在叠加式增加。

推荐学习:mysql视频教程

以上就是MySQL中的流式查询及游标查询方式(总结分享)的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/279685.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
怎样在Word中快速移除超链接_Word超链接打断全指南
上一篇 2026年10月17日 14:02:08
sql中!=是什么意思
下一篇 2025年11月11日 07:00:14

相关推荐

  • 归纳整理MySQL存储过程参数的用法及说明

    归纳整理MySQL存储过程参数的用法及说明归纳整理MySQL存储过程参数的用法及说明归纳整理MySQL存储过程参数的用法及说明归纳整理MySQL存储过程参数的用法及说明

    本篇文章给大家带来了关于mysql的相关知识,主要介绍了mysql存储过程参数的用法及说明,mysql存储过程的参数共有三种:in、out 、inout,下面一起来看一下,希望对大家有帮助。 推荐学习:mysql视频教程 MySQL存储过程的参数 MySQL存储过程的参数共有三种: INOUT IN…

    2026年10月17日 • 用户投稿
    100
  • MySQL中的日期时间类型与格式化方式总结

    MySQL中的日期时间类型与格式化方式总结MySQL中的日期时间类型与格式化方式总结MySQL中的日期时间类型与格式化方式总结MySQL中的日期时间类型与格式化方式总结

    本篇文章给大家带来了关于mysql的相关知识,主要介绍了mysql中的日期时间类型与格式化方式,mysql中常用的几种时间类型有:date、datetime、time、year、timestamp,下面一起来看一下,希望对大家有帮助。 推荐学习:mysql视频教程 【1】MySQL中的日期时间类型 …

    2026年10月17日 • 用户投稿
    100
  • MySQL分表后如何高效解决排序分页查询难题?

    MySQL分表后如何高效解决排序分页查询难题?MySQL分表后如何高效解决排序分页查询难题?MySQL分表后如何高效解决排序分页查询难题?MySQL分表后如何高效解决排序分页查询难题?

    MySQL分表后的排序分页查询挑战 数据库分表虽然提升了性能,却给排序分页查询带来了新的难题。本文探讨两种常用方法及其局限性。 方法一:全表查询,内存排序 此方法需查询所有分表的前N*页数条数据,进行内存排序后返回指定页的数据。虽然支持跳页,但随着页数增加,查询效率和内存消耗将急剧增长,成为性能瓶颈…

    2026年10月17日 • 用户投稿
    000
  • MySQL数据库线上修改表结构的方法

    MySQL数据库线上修改表结构的方法MySQL数据库线上修改表结构的方法MySQL数据库线上修改表结构的方法MySQL数据库线上修改表结构的方法

    本篇文章给大家带来了关于mysql的相关知识,MySQL有一个把锁,叫做MDL元数据锁,当对表修改的时候,会自动给表加上这把锁,也就是不需要自己显式使用,下面介绍一下MySQL数据库线上修改表结构的方法,希望对大家有帮助。 推荐学习:mysql视频教程 一、MDL元数据锁 在修改表结构之前,先来看下…

    2026年10月17日 • 用户投稿
    100
  • 实例详解MySQL索引最左匹配原则

    实例详解MySQL索引最左匹配原则实例详解MySQL索引最左匹配原则实例详解MySQL索引最左匹配原则实例详解MySQL索引最左匹配原则

    本篇文章给大家带来了关于mysql的相关知识,最左匹配原则就是指在联合索引中,如果你的SQL语句中用到了联合索引中的最左边的索引,那么这条SQL语句就可以利用这个联合索引去进行匹配,下面介绍了关于MySQL索引最左匹配原则的相关资料,希望对大家有帮助。 推荐学习:mysql视频教程 准备 为了方面后…

    2026年10月17日 • 用户投稿
    100
  • 数据库慢查询监控与优化

    数据库慢查询监控与优化数据库慢查询监控与优化数据库慢查询监控与优化数据库慢查询监控与优化

    慢查询可以通过监控和优化来提高数据库性能。1.监控方法包括使用慢查询日志和第三方工具,关注响应时间、执行计划和资源消耗。2.优化策略涉及重构查询、调整索引、分区表和使用缓存。持续监控和定期优化是关键。 你问到数据库慢查询监控与优化,这是个非常重要的主题,特别是在处理大规模数据应用时。慢查询不仅会影响…

    2026年10月17日 • 用户投稿
    100
  • MySQL乐观锁和悲观锁具体实现

    MySQL乐观锁和悲观锁具体实现MySQL乐观锁和悲观锁具体实现MySQL乐观锁和悲观锁具体实现MySQL乐观锁和悲观锁具体实现

    本篇文章给大家带来了关于mysql的相关知识,其中主要介绍了MySQL乐观锁和悲观锁具体实现,文章围绕主题展开详细的内容介绍,下面一起来看一下,希望对大家有帮助。 推荐学习:mysql视频教程 对于MySQL中的乐观锁和悲观锁,可能很多的开发者还不是很熟悉,并不知道其中具体是如何实现的。本文就针对这…

    2026年10月17日 • 用户投稿
    2000
  • Linux如何安全配置Mysql数据库

    Linux如何安全配置Mysql数据库Linux如何安全配置Mysql数据库Linux如何安全配置Mysql数据库Linux如何安全配置Mysql数据库

    本篇文章给大家带来的内容是介绍在linux中如何安全配置mysql数据库,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 目录: 1.修改mysql管理员账号root的密码(2种方法) 2.修改mysql管理员账号root 3.mysql管理员root账号密码遗忘解决办法(2种方法)…

    2026年10月17日 • 用户投稿
    000
  • 聊聊GitHub是怎么做好 MySQL 高可用性的

    聊聊GitHub是怎么做好 MySQL 高可用性的聊聊GitHub是怎么做好 MySQL 高可用性的聊聊GitHub是怎么做好 MySQL 高可用性的聊聊GitHub是怎么做好 MySQL 高可用性的

    github是怎么做好 mysql 高可用性的?下面本篇文章就来带大家分享一下,希望对大家有所帮助。 Github 使用 MySQL 数据库作为所有非 git 事务的数据存储。数据库的可用性对 Github 的正常运行而言至关重要。无论是 Github 网站本身,还是 Github API,身份验证…

    2026年10月17日 • 用户投稿
    100
  • MySQL中关于datetime、date、time、str之间的转化与比较

    MySQL中关于datetime、date、time、str之间的转化与比较MySQL中关于datetime、date、time、str之间的转化与比较MySQL中关于datetime、date、time、str之间的转化与比较MySQL中关于datetime、date、time、str之间的转化与比较

    本篇文章给大家带来了关于mysql的相关知识,其中主要介绍了关于datatime、data、time、str之间的转化与比较的相关问题,下面一起来看一下,希望对大家有帮助。 推荐学习:mysql视频教程 datetime、date、time、str之间的转化与比较 SELECT NOW(),CURD…

    2026年10月17日 • 用户投稿
    100
  • 一文搞懂MySQL索引下推

    一文搞懂MySQL索引下推一文搞懂MySQL索引下推一文搞懂MySQL索引下推一文搞懂MySQL索引下推

    本篇文章给大家带来了关于mysql的相关知识,其中主要介绍了关于索引下推的相关内容,索引条件下推也叫索引下推,英文全称index condition pushdown,简称icp,用于优化数据查询,下面一起来看一下,希望对大家有帮助。 推荐学习:mysql视频教程 SELECT 语句执行过程 MyS…

    2026年10月17日 • 用户投稿
    200
  • Maestro存储过程参数添加指南

    Maestro存储过程参数添加指南Maestro存储过程参数添加指南Maestro存储过程参数添加指南Maestro存储过程参数添加指南

    启动SQL Maestro for MySQL应用程序。 通过主菜单进入数据库浏览器界面。 建立与目标数据库的连接。 展开数据库对象树,找到需要操作的存储过程。 存了个图 视频图片解析/字幕/剪辑,视频高清保存/图片源图提取 17 查看详情 右键点击指定的存储过程,选择“编辑过程”以打开参数设置界面…

    2026年10月17日 • 用户投稿
    100
  • 遇事不慌,先记录:mysql in慢查询优化

    遇事不慌,先记录:mysql in慢查询优化遇事不慌,先记录:mysql in慢查询优化遇事不慌,先记录:mysql in慢查询优化遇事不慌,先记录:mysql in慢查询优化

    本篇文章给大家带来了关于mysql慢查询优化的问题, 我会一步步带大家分析sql、检查并优化,下面一起来看一下,希望对大家有帮助。 记一次mysql慢查询优化——生产环境待办列表现场演示5~6s才加载出来结果;顿时,产品经理的脸挂不住了,作为多年经验的老开发,心想完犊子,脸啪啪滴。 不过,秉着多年的…

    2026年10月17日 • 用户投稿
    100
  • mysql的user表在哪

    mysql的user表在哪mysql的user表在哪mysql的user表在哪mysql的user表在哪

    user表在名为“mysql”的数据库中。MySQL在安装时会自动创建一个名为“mysql”的数据库,mysql数据库中存储的都是用户权限表;而user表是mysql数据库中最重要的一个权限表,用来记录允许连接到服务器的账号信息。user表里启用的所有权限都是全局级的,适用于所有数据库。 本教程操作…

    2026年10月17日 • 用户投稿
    100
  • mysql distinct怎么用

    mysql distinct怎么用mysql distinct怎么用mysql distinct怎么用mysql distinct怎么用

    在mysql中,distinct关键字用于过滤重复数据,它可以对数据表中一个或多个字段重复的数据进行过滤,只返回其中的一条数据给用户;distinct关键字需要和SELECT语句一起使用,语法“SELECT DISTINCT column1, column2, … FROM table_…

    2026年10月17日 • 用户投稿
    300
  • mysql中什么是filesort

    mysql中什么是filesortmysql中什么是filesortmysql中什么是filesortmysql中什么是filesort

    在mysql中,filesort是指文件排序,是通过相应的排序算法,将取得的数据在内存中进行排序。filesort分两种:1、双路排序,是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行指针信息,然后在sort buffer 中进行排序;2、单路排序,是一次性取出满足条件行的所有字段,然…

    2026年10月17日 • 用户投稿
    100
  • 安装了mysql但是服务中没有 手动注册windows服务方法

    mysql服务未在windows服务中显示是因为安装时未正确配置或添加服务。要手动注册mysql服务,1)以管理员身份打开命令提示符,2)导航到mysql的bin目录,3)执行命令“mysqld –install mysql –defaults-file=’c:p…

    2026年10月17日
    200
  • mysql中什么是事务处理

    mysql中什么是事务处理mysql中什么是事务处理mysql中什么是事务处理mysql中什么是事务处理

    在mysql中,事务处理是一种机制,用来管理必须成批执行的MySQL操作,以保证数据库不包含不完整的操作结果;事务处理可以用来维护数据库的完整性,可保证成批的MySQL操作不会中途停止,它们要么完全执行,要么完全不执行。 本教程操作环境:windows7系统、mysql8版本、Dell G3电脑。 …

    2026年10月17日 • 用户投稿
    300
  • mysql中执行计划是什么

    mysql中执行计划是什么mysql中执行计划是什么mysql中执行计划是什么mysql中执行计划是什么

    在mysql中,执行计划是数据库提供给用户的一套对sql语句进行解析、分析、优化功能的工具。执行计划的作用有:1、展示表的读取顺序;2、数据读取操作的类型;3、展示哪些索引是可以使用的;4、展示哪些索引是实际上使用的;5、展示表之间的引用关系;6、展示每张表被查询的行数。 本教程操作环境:windo…

    2026年10月17日 • 用户投稿
    100
  • MySQL详解之事务隔离机制与实现原理

    MySQL详解之事务隔离机制与实现原理MySQL详解之事务隔离机制与实现原理MySQL详解之事务隔离机制与实现原理MySQL详解之事务隔离机制与实现原理

    本篇文章给大家带来了关于mysql的相关知识, 其中主要介绍了mysql事务的使用和其存在长事务的风险、mysql 的事务及其特性,并发事务带来的问题、事务的隔离级别与演示,单版本控制锁以及多版本并发控制 mvcc等内容,下面一起来看一下,希望对大家有帮助。 推荐学习:mysql视频教程 一、MyS…

    2026年10月17日 • 用户投稿
    100

发表回复

登录后才能评论
关注微信