MyBatis Plus 解决大数据量查询慢问题

news2024/9/27 7:19:37
  • 常规查询

  • 流式查询

  • 游标查询


大数据量操作的场景大致如下:

  • 数据迁移

  • 数据导出

  • 批量处理数据

在实际工作中当指定查询数据过大时,我们一般使用分页查询的方式一页一页的将数据放到内存处理。但有些情况不需要分页的方式查询数据或分很大一页查询数据时,如果一下子将数据全部加载出来到内存中,很可能会发生OOM(内存溢出);而且查询会很慢,因为框架耗费大量的时间和内存去把数据库查询的结果封装成我们想要的对象(实体类)。

举例:在业务系统需要从 MySQL 数据库里读取 100w 数据行进行处理,应该怎么做?

做法通常如下:

  • 常规查询: 一次性读取 100w 数据到 JVM 内存中,或者分页读取

  • 流式查询: 建立长连接,利用服务端游标,每次读取一条加载到 JVM 内存(多次获取,一次一行)

  • 游标查询: 和流式一样,通过 fetchSize 参数,控制一次读取多少条数据(多次获取,一次多行)

常规查询

默认情况下,完整的检索结果集会将其存储在内存中。在大多数情况下,这是最有效的操作方式,并且由于 MySQL 网络协议的设计,因此更易于实现。

举例:

假设单表 100w 数据量,一般会采用分页的方式查询:

@Mapper
public interface BigDataSearchMapper extends BaseMapper<BigDataSearchEntity> {
 
    @Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ")
    Page<BigDataSearchEntity> pageList(@Param("page") Page<BigDataSearchEntity> page, @Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper);
 
}

注:该示例使用的 MybatisPlus

该方式比较简单,如果在不考虑 LIMIT 深分页优化情况下,估计你的数据库服务器就噶皮了,或者你能等上几十分钟或几小时,甚至几天时间检索数据

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

流式查询

流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果。流式查询的好处是能够降低内存使用。

如果没有流式查询,我们想要从数据库取 100w 条记录而又没有足够的内存时,就不得不分页查询,而分页查询效率取决于表设计,如果设计的不好,就无法执行高效的分页查询。因此流式查询是一个数据库访问框架必须具备的功能。

MyBatis 中使用流式查询避免数据量过大导致 OOM ,但在流式查询的过程当中,数据库连接是保持打开状态的,因此要注意的是:

  • 执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭。

  • 必须先读取(或关闭)结果集中的所有行,然后才能对连接发出任何其他查询,否则将引发异常。

MyBatis 流式查询接口

MyBatis 提供了一个叫 org.apache.ibatis.cursor.Cursor 的接口类用于流式查询,这个接口继承了 java.io.Closeable 和 java.lang.Iterable 接口,由此可知:

  • Cursor 是可关闭的;

  • Cursor 是可遍历的。

除此之外,Cursor 还提供了三个方法:

  • isOpen(): 用于在取数据之前判断 Cursor 对象是否是打开状态。只有当打开时 Cursor 才能取数据;

  • isConsumed(): 用于判断查询结果是否全部取完。

  • getCurrentIndex(): 返回已经获取了多少条数据

使用流式查询,则要保持对产生结果集的语句所引用的表的并发访问,因为其 查询会独占连接,所以必须尽快处理

为什么要用流式查询?

如果有一个很大的查询结果需要遍历处理,又不想一次性将结果集装入客户端内存,就可以考虑使用流式查询;

分库分表场景下,单个表的查询结果集虽然不大,但如果某个查询跨了多个库多个表,又要做结果集的合并、排序等动作,依然有可能撑爆内存;详细研究了sharding-sphere的代码不难发现,除了group byorder by字段不一样之外,其他的场景都非常适合使用流式查询,可以最大限度的降低对客户端内存的消耗。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

游标查询

对大量数据进行处理时,为防止内存泄漏情况发生,也可以采用游标方式进行数据查询处理。这种处理方式比常规查询要快很多。

当查询百万级的数据的时候,还可以使用游标方式进行数据查询处理,不仅可以节省内存的消耗,而且还不需要一次性取出所有数据,可以进行逐条处理或逐条取出部分批量处理。一次查询指定 fetchSize 的数据,直到把数据全部处理完。

Mybatis 的处理加了两个注解:@Options 和 @ResultType

@Mapper
public interface BigDataSearchMapper extends BaseMapper<BigDataSearchEntity> {
 
    // 方式一 多次获取,一次多行
    @Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ")
    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 1000000)
    Page<BigDataSearchEntity> pageList(@Param("page") Page<BigDataSearchEntity> page, @Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper);
 
    // 方式二 一次获取,一次一行
    @Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ")
    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 100000)
    @ResultType(BigDataSearchEntity.class)
    void listData(@Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper, ResultHandler<BigDataSearchEntity> handler);
 
}

@Options

  • ResultSet.FORWORD_ONLY:结果集的游标只能向下滚动

  • ResultSet.SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变

  • ResultSet.SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变

  • fetchSize:每次获取量

@ResultType

  • @ResultType(BigDataSearchEntity.class):转换成返回实体类型

注意:返回类型必须为 void ,因为查询的结果在 ResultHandler 里处理数据,所以这个 hander 也是必须的,可以使用 lambda 实现一个依次处理逻辑。

注意:

虽然上面的代码中都有 @Options 但实际操作却有不同:

  • 方式一是多次查询,一次返回多条;

  • 方式二是一次查询,一次返回一条;

原因:

Oracle 是从服务器一次取出 fetch size 条记录放在客户端,客户端处理完成一个批次后再向服务器取下一个批次,直到所有数据处理完成。

MySQL 是在执行 ResultSet.next() 方法时,会通过数据库连接一条一条的返回。flush buffer 的过程是阻塞式的,如果网络中发生了拥塞,send buffer 被填满,会导致 buffer 一直 flush 不出去,那 MySQL 的处理线程会阻塞,从而避免数据把客户端内存撑爆。

非流式查询和流式查询区别:

  • 非流式查询:内存会随着查询记录的增长而近乎直线增长。

  • 流式查询:内存会保持稳定,不会随着记录的增长而增长。其内存大小取决于批处理大小BATCH_SIZE的设置,该尺寸越大,内存会越大。所以BATCH_SIZE应该根据业务情况设置合适的大小。

另外要切记每次处理完一批结果要记得释放存储每批数据的临时容器,即上文中的gxids.clear();

 

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

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

相关文章

实用工具指南:2个提升效率的互联网利器

工具一&#xff1a; 字体酷站是全球最大的字体网址导航网站&#xff0c;收录了大量优质的字体素材和字体设计资源。该网站拥有丰富多样的字体分类和标签&#xff0c;用户可以根据需求选择不同类型、不同风格的字体&#xff0c;如商务字体、手写字体、卡通字体等。同时&#xf…

B+树单表超过2500万行的性能影响

&#xff08;有许多人是用青春的幸福作成功的代价的。——莫扎特&#xff09; B树 关于B树的原理请查看这篇文章 分析 MySQL采用了索引组织表的形式组织数据&#xff0c;叶子节点存储数据&#xff0c;非叶子节点存储主键与页面号的映射关系。若用户的主键长度是8字节时&…

基于MATLAB涡度通量数据处理

查看原文>>>基于MATLAB涡度通量数据处理实践技术应用 【内容简述】&#xff1a; 基于MATLAB语言、以实践案例为主&#xff0c;提供代码、原理与操作结合1、以涡度通量塔的高频观测数据为例&#xff1a;基于MATLAB上机操作2、涡度通量观测基本概况&#xff1a;观测技术…

用友 畅捷通T+ DownloadProxy.aspx 任意文件读取漏洞

1. 漏洞描述 用友 畅捷通T DownloadProxy.aspx文件存在任意文件读取漏洞&#xff0c;攻击者通过漏洞可以获取服务器上的敏感文件. 2.FOFA app"畅捷通-TPlus" 3.漏洞复现 登录页面 验证POC /tplus/SM/DTS/DownloadProxy.aspx?preload1&Path../../Web.Confi…

2.3 逻辑代数的基本公式和常用公式

博主介绍&#xff1a;一个爱打游戏的计算机专业学生 博主主页&#xff1a;夏驰和徐策 所属专栏&#xff1a;程序猿之数字电路 学习目标&#xff1a; 1. 学习基本概念&#xff1a;首先&#xff0c;了解逻辑代数的基本概念和术语&#xff0c;如命题、逻辑运算符&#xff08;与…

探索上位机编程的挑战与乐趣

上位机编程的难度取决于多个因素&#xff0c;包括您的编程经验、所使用的编程语言和开发工具、应用程序的复杂程度等等。 如果您具备一定的编程经验并且熟悉所选的编程语言和开发工具&#xff0c;那么上位机编程可能相对容易上手。上位机编程通常涉及与外部设备&#xff08;如…

Unity入门1——窗口布局

文章目录 一、Hierarchy 窗口 二、Scene 窗口 三、工具栏 四、Game 窗口 五、Project 工程窗口 六、Inspector 窗口 七、Console 窗口 一、Hierarchy 窗口 ​ 在这里创建对象、操作对象。 ​ 快捷键&#xff1a;F2&#xff1a;对象改名 ​ CtrlC&#xff1a;复制 ​ CtrlV&…

avue curd 中的配置项插槽使用

效果图&#xff1a;&#xff08;新增时候的步骤条&#xff0c;以为是设置透明度是0-1中的小数 avue中步骤是整数 于是使用到插槽用element-ui&#xff09; html&#xff1a; <template slot"opacityForm"><el-row class"row"><el-slider v-…

ABAP:后台执行JOB报错问题

错误&#xff1a;CL_GUI_CUSTOM_CONTAINERCP生成容器错误&#xff0c;主要在OOALV中运用到 原因&#xff1a;是由于我们在JOB后台执行的时候无法打开GUI端而报错的 此时&#xff0c;我们就需要在程序中去规避后台执行这一段逻辑&#xff0c;可以通过SY-BATCH解决&#xff0c;当…

今天终于知道了,阿里巴巴 P8、P9 及以上到底是什么水平?

做人做事不能万事向钱看&#xff0c;但是钱这个东西很多时候都反映了事物的价值以及一个人的能力水平。 比如阿里P8、P9 这些拿着高薪的程序员他们的技术水平就一直是大家好奇的。 今天在逛某乎的时候就恰好看见了一个几百万人关注的问题&#xff1a; 阿里的高p们动辄百万以上…

探索地理空间的无限可能:GIS地图的应用与发展

随着科技的飞速发展和数字化时代的来临&#xff0c;GIS地图正成为一个强大的工具&#xff0c;为我们提供了更准确、全面的地理空间数据和智能化的解决方案。GIS地图集成了地理信息、空间分析和可视化技术&#xff0c;为我们打开了一个全新的世界&#xff0c;让我们能够更好地理…

linux进阶 --- chrony服务器

chrony服务器 &#xff08;1&#xff09;定义&#xff1a; 是一个开源自由的网络时间协议NTP的客户端与服务器端软件。让计算机保持系统时钟与时钟服务器&#xff08;NTP&#xff09;同步。chrony由两个程序组成&#xff0c;chronyd&#xff08;服务器端&#xff09;和chronyc…

接口如何运用pytest+HttpRunner展开测试?

目录 前言&#xff1a; 一、 什么是接口测试 二、 引入自动化背景 三、 自动化技术选型 四、 自动化测试用例 五、自动化成果 前言&#xff1a; pytest和HttpRunner都是Python编程语言中常用的接口测试框架。 pytest是一种成熟的、灵活的、社区支持良好的测试框架&…

【问题记录】Visual Studio 下的Qt工程无法打开 “xxx.ui“ 文件和LNK1104 无法打开文件“Qt5Cored.lib”错误

环境 Windows 11 家庭中文版Microsoft Visual Studio Community 2022 (64 位) - Current 版本 17.5.3qt-vsaddin-msvc2022-2.9.1-rev.06 问题产生 VS下Qt环境准备好后&#xff0c;创建了Qt工程然后点击 Form Files 下的 “xxx.ui” 文件&#xff0c;在弹出 Qt 设计师 界面后…

全网最详细,性能测试-连接池与线程详解,8年测试总结...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 连接池 1、什么是…

基础硬件查漏补缺

1、开发板常见物理设备接口 跳线&#xff08;Jumper&#xff09;&#xff1a;跳线是起短接作用的微型插头&#xff0c;与多针微型插座配合使用。用来调整参数&#xff0c;扩大主板通用性。一般的跳线是方形塑料帽&#xff0c;其内部是金属&#xff0c;也叫做跳帽。 跳线有三代…

Jetpack Compose —— 深入理解 Column 布局

Jetpack Compose 是 Android 最新的 UI 工具包&#xff0c;其中的 Column 是一种常用的布局组件。在本篇我们将深入了解 Column 的使用方法和特性&#xff0c;以帮助您更好地理解和应用 Jetpack Compose 中的 Column 布局。 一、什么是 Column Column 是 Jetpack Compose 中用…

一个软件要经历过什么测试才能上线?

一、编写目的 明确软件测试工作的开始和结束标准。 二、软件测试合格标准 以上比例为错误占总测试模块的比例。 三、缺陷修复率标准 1) A、B、C级错误修复率应达到100% 2) D级错误修复率应达到96%以上 四、覆盖率标准 测试需求执行覆盖率应达到100%&#xff08;业务测…

PyEcharts入门到精通

一、PyEcharts介绍 版本 pyecharts分为v0.5.x和v1两个大版本&#xff0c;v0.5.x和v1间不兼容&#xff0c;v1是一个全新的版本 经开发团队决定&#xff0c;0.5.x版本将不再进行维护&#xff0c;我们不再使用v0.5.x 新版本系列将从v1.0.0开始&#xff0c;仅支持Python 3.6 将…

SD SD-DN 外向交货单保存后增强点

外向交货单保存后 下发外围系统 se18:LE_SHP_DELIVERY_PROC 在se19:ZSHP_DELIVERY_PROC_2