0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

jf_ro2CN3Fa 来源:CSDN 2023-01-16 10:17 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

  • 常规查询
  • 流式查询
  • 游标查询

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

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

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

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

做法通常如下:

  • 常规查询: 一次性读取 100w 数据到 JVM 内存中,或者分页读取
  • 流式查询: 建立长连接,利用服务端游标,每次读取一条加载到 JVM 内存(多次获取,一次一行)
  • 游标查询: 和流式一样,通过 fetchSize 参数,控制一次读取多少条数据(多次获取,一次多行)

常规查询

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

举例:

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

@Mapper
publicinterfaceBigDataSearchMapperextendsBaseMapper<BigDataSearchEntity>{

@Select("SELECTbds.*FROMbig_data_searchbds${ew.customSqlSegment}")
PagepageList(@Param("page")Pagepage,@Param(Constants.WRAPPER)QueryWrapperqueryWrapper);

}

注:该示例使用的 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.Closeablejava.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
publicinterfaceBigDataSearchMapperextendsBaseMapper<BigDataSearchEntity>{

//方式一多次获取,一次多行
@Select("SELECTbds.*FROMbig_data_searchbds${ew.customSqlSegment}")
@Options(resultSetType=ResultSetType.FORWARD_ONLY,fetchSize=1000000)
PagepageList(@Param("page")Pagepage,@Param(Constants.WRAPPER)QueryWrapperqueryWrapper);

//方式二一次获取,一次一行
@Select("SELECTbds.*FROMbig_data_searchbds${ew.customSqlSegment}")
@Options(resultSetType=ResultSetType.FORWARD_ONLY,fetchSize=100000)
@ResultType(BigDataSearchEntity.class)
voidlistData(@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();

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据库
    +关注

    关注

    7

    文章

    3994

    浏览量

    67849
  • MySQL
    +关注

    关注

    1

    文章

    897

    浏览量

    29253
  • 数据迁移
    +关注

    关注

    0

    文章

    87

    浏览量

    7220

原文标题:MyBatis Plus 解决大数据量查询慢问题

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    电能质量在线监测装置的采集频率调整对数据存储有什么影响?

    电能质量在线监测装置的采集频率调整,核心影响是 “数据量与存储资源的动态平衡” :采集频率越高,单位时间产生的数据量越大,对存储容量、存储周期、硬件损耗的压力越显著;反之则数据量减少,存储压力降
    的头像 发表于 12-11 10:41 312次阅读
    电能质量在线监测装置的采集频率调整对<b class='flag-5'>数据</b>存储有什么影响?

    rt_sem_take卡住导致线程无法正常运行怎么解决?

    串口接收数据后release信号,接收线程take sem,高频大数据量接受数据,运行一段时间后接受线程suspend,但是release正常释放 出现问题问题后查看信息如下:
    发表于 09-23 08:17

    淘宝/天猫:使用物流查询API实时显示包裹位置,减少客服咨询

    ​  引言 在电商平台的日常运营中,物流咨询往往占据客服工作的40%以上。买家频繁询问"我的包裹到哪里了?"不仅增加客服压力,还影响用户体验。本文将介绍如何通过 物流查询API 实时显示包裹位置
    的头像 发表于 09-22 14:34 342次阅读
    淘宝/天猫:使用物流<b class='flag-5'>查询</b>API实时显示包裹位置,减少客服咨询<b class='flag-5'>量</b>

    数据查询分析与SQL优化实战技巧

    今天,我将分享我在处理数千次数据库性能问题中积累的实战经验,帮助你系统掌握查询分析与SQL优化的核心技巧。无论你是刚入门的运维新手,还是有一定经验的工程师,这篇文章都将为你提供实用的解决方案。
    的头像 发表于 09-08 09:34 664次阅读

    MySQL查询终极优化指南

    作为一名在生产环境摸爬滚打多年的运维工程师,我见过太多因为查询导致的线上故障。今天分享一套经过实战检验的MySQL查询分析与索引优化方法论,帮你彻底解决
    的头像 发表于 08-13 15:55 672次阅读

    cypress3014怎么查看USB走线每帧传输的图像数据量

    你好,请问怎么查看USB 走线每帧传输的图像数据量
    发表于 05-14 06:12

    ClickHouse 的“独孤九剑”:极速查询的终极秘籍

    引言 在大数据时代的江湖,数据量呈爆炸式增长,如何高效地处理和分析海量数据成为了一个关键问题。各路英雄豪杰纷纷亮出自己的绝技,争夺数据处理的巅峰宝座。而在这场激烈的角逐中,ClickH
    的头像 发表于 04-07 13:34 575次阅读
    ClickHouse 的“独孤九剑”:极速<b class='flag-5'>查询</b>的终极秘籍

    STM32F429以太网外设数据处理上限是多少?

    无法通信-通信延时-通信恢复,wireshark数据暂未获取到。 请帮忙分析以上现象是否为429的MAC核无法支持大数据量的冲刷,即使MAC过滤减轻了应用层的压力,在MAC硬件层仍会造成拥塞或某种溢出。谢谢
    发表于 03-13 06:52

    RAM容量不足导致的数据溢出如何预防和处理?

    在 STM32F411 中,RAM 容量是有限的,特别是在进行复杂的数据处理和存储时,可能会遇到数据溢出问题。数据溢出是指程序运行时,数据超出了 RAM 的分配区域,导致程序崩溃或
    发表于 03-07 16:09

    HAL库SPI DMA批量传输数据量最大为2^16,有没有办法改成上限为2^32?

    HAL库SPI DMA批量传输数据量最大为2^16,有没有办法改成上限为2^32
    发表于 03-07 13:02

    企业并购中SAP系统的三大数据转型挑战以及来如何应对?

    SNP探讨并购中数据挑战:系统不匹配、停机时间长、数据量大。提出解决方案:调整系统一致性、最小化停机时间、管理数据量。通过CrystalBridge®和OutboardERP实现成功案例。
    的头像 发表于 02-27 17:02 556次阅读

    调试16位adc芯片ads8328时转换后的数据波动100个数据量转换后的数据有波动,而且测量值比理论值小,为什么?

    调试16位adc芯片ads8328时转换后的数据波动100个数据量转换后的数据有波动,而且测量值比理论值小。输入电压使用安捷伦的数字电压源给的,基准时REF3120,2.048V的,都是TI的产品,以下是我的硬件电路和测量的
    发表于 01-24 06:52

    一种轻分表方案-MyBatis拦截器分表实践

    作者:京东零售 张均杰 背景 部门内有一些亿级别核心业务表增速非常快,增量日均100W,但线上业务只依赖近一周的数据。随着数据量的迅速增长,SQL频发,数据库性能下降,系统稳定性受到
    的头像 发表于 01-23 17:38 676次阅读

    系统要求20微秒采集一次数据,每次数据量4.8Kb,总的速率为240Mbps,ADC0XD1520RB评估板能否满足需求?

    有几个问题请教各位专家: 1、我的系统要求20微秒采集一次数据(单通道模式下3Gsps),每次数据量4.8Kb,总的速率为240Mbps,ADC0XD1520RB这个评估板能否满足需求。缓冲容量
    发表于 12-26 07:43

    缓存对大数据处理的影响分析

    缓存对大数据处理的影响显著且重要,主要体现在以下几个方面: 一、提高数据访问速度 在大数据环境中,数据存储通常采用分布式存储系统,数据量庞大
    的头像 发表于 12-18 09:45 1134次阅读