面试官:从 MySQL 读取 100w 数据进行处理,应该怎么做?

因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享

点击关注#互联网架构师公众号,领取架构师全套资料 都在这里6c52b5c3001c82df4d107c6c47e305ed.png

0、2T架构师学习资料干货分

上一篇:ChatGPT研究框架(80页PPT,附下载)

大家好,我是互联网架构师!

背景

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

  • 数据迁移

  • 数据导出

  • 批量处理数据

在实际工作中当指定查询数据过大时,我们一般使用分页查询的方式一页一页的将数据放到内存处理。但有些情况不需要分页的方式查询数据或分很大一页查询数据时,如果一下子将数据全部加载出来到内存中,很可能会发生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 深分页优化情况下,估计你的数据库服务器就噶皮了,或者你能等上几十分钟或几小时,甚至几天时间检索数据。

流式查询

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

如果没有流式查询,我们想要从数据库取 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字段不一样之外,其他的场景都非常适合使用流式查询,可以最大限度的降低对客户端内存的消耗。

游标查询

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

当查询百万级的数据的时候,还可以使用游标方式进行数据查询处理,不仅可以节省内存的消耗,而且还不需要一次性取出所有数据,可以进行逐条处理或逐条取出部分批量处理。一次查询指定 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();

原文:blog.csdn.net/qq_48157004/article/details/128356734

1、Alibaba开源内网高并发编程手册.pdf

2、2T架构师学习资料干货分享

3、10000+TB 资源,阿里云盘,牛逼!!

4、基本涵盖了Spring所有核心知识点总结

  · END ·

最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。

fbe352bcb3f342e29f0bcaa67daa31b1.png

如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描上方二维码关注一下,您的支持是我坚持写作最大的动力。

求一键三连点赞、转发、在看。

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

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

相关文章

Spring Boot 实现日志链路追踪,无需引入组件,让日志定位更方便!

因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享 点击关注#互联网架构师公众号&#xff0c;领取架构师全套资料 都在这里 0、2T架构师学习资料干货分 上一篇&#xff1a;ChatGPT研究框架&#xff08;80页PPT&#xff0c;附下载&#xff09;…

chatgpt赋能python:Python如何将PDF转换为Word文档

Python如何将PDF转换为Word文档 在现代电脑使用的日常工作中&#xff0c;PDF格式的文档已经变得很普遍。这种文件格式十分方便&#xff0c;但是有时候可能需要将PDF文件转换为Word文档。幸运的是&#xff0c;Python提供了多种方法来实现这个目标。 为什么要将PDF转换为Word&a…

chatgpt赋能python:Python基础教程:如何利用Python进行地区查询

Python基础教程&#xff1a;如何利用Python进行地区查询 在现代社会&#xff0c;人们越来越关注自己所处的地理位置和周边环境。这就导致了地区查询变得越来越流行&#xff0c;因为它可以让人们更加方便地获取自己想要的信息。 Python作为一门强大的编程语言&#xff0c;不仅…

很多人都去考了计算机二级证书,它真的有用吗?来看看吧

我相信在大学期间,很多人都会选择自考计算机二级的证书,那么就有不少人提出疑问:计算机二级证书真的有用吗? 其实我觉得不应该去凭借一个观点去认为他是否有用,主要还是你掌握了多少知识。我认为大学本身就是一个去不断积累知识的过程,重要的不是你拿的这个证书的结果,…

Tsai库---分享一个好用的时间序列库

分享一个好用的时间序列库 tsai库github地址&#xff1a;https://github.com/timeseriesAI/tsai 使用手册&#xff1a;https://timeseriesai.github.io/tsai/ 描述 tsai是一个先进的时间序列和序列深度学习库。是建立在Pytorch &fastai之上的开源深度学习包&#xff0c;可…

计算机信息处理技术员初级难不难,考信息处理技术员之前,这些问题你要知道!...

信息处理技术员具有计算机与信息处理的基础知识&#xff0c;能根据应用部门的要求&#xff0c;熟练使用计算机有效地、安全地进行信息处理操作&#xff0c;能对个人计算机系统进行日常维护&#xff0c;具有助理工程师(或技术员)的实际工作能力和业务水平。 01信息处理技术员是职…

charles证书过期-mac

手机已安装证书并且信任还是抓不到包&#xff0c;大概率是charles证书过期了 1.重置证书 help > SSL Proxying >Reset Charles Root Certificate... 2.点击Reset 3.在启动台打开「钥匙串访问」 找到对应证书 设置为「始终信任」

计算机考证可以退钱吗?

可以&#xff01;计算机考试在报名期间可以登录报名系统进行退费申请&#xff0c;申请成功后&#xff0c;考试费用将按原支付渠道退回考点&#xff1b;通过集体考点报考的考生&#xff0c;将按原支付渠道退回考点&#xff0c;再由考点退还给考生。由于疫情原因&#xff0c;2020…

中级通信工程师证书会过期吗

通信行业中一般的证书都是有有效期的&#xff0c;比如的华为认证&#xff0c;有效期是3年&#xff0c;到证书持有者在证书超过有效期之前&#xff0c;可以通过再次通过考试或者通过本技术领域的更高级别认证的任意一门考试来延期证书的有效期。那么中级通信工程师证书有有效期吗…

图灵测试是什么?为什么AlphaGo那么牛却过不了?

导读&#xff1a;本文将介绍人工智能的检测手段——图灵测试。 作者&#xff1a;杜振东 涂铭 来源&#xff1a;大数据DT&#xff08;ID&#xff1a;hzdashuju&#xff09; 01 图灵测试相关背景 1946年&#xff0c;冯诺依曼发明了第一台计算机&#xff0c;这被后人称为20世纪最先…

python贪吃蛇游戏源码

python贪吃蛇游戏源码 源码如下&#xff1a; 如果没有安装pygame游戏库&#xff0c;需要安装后才能正常使用 pygame游戏库获取如下&#xff1a; https://pypi.org/project/pygame/ 源码如下&#xff1a; import random import sys import time import pygame from pygame.l…

Android贪吃蛇游戏实现

说明&#xff1a;贪吃蛇游戏是一款比较经典的休闲游戏&#xff0c;这是我做的第一个Android项目&#xff0c;会存在一些问题&#xff0c;文章包括项目的部分源码以及运行界面的一些图片&#xff0c;项目也参考学习了许多大佬的文章&#xff0c;会在文章最后面贴出参考文章&…

VC版的贪吃蛇游戏

学C的时候&#xff0c;课程设计编写了C版的贪吃蛇游戏&#xff0c;当时&#xff0c;将很多的东西都分装在了Snake类中&#xff0c;所以&#xff0c;将其移植到VC中&#xff0c;只需将Snake类稍作修改&#xff0c;然后添加到VC中即可。 此处&#xff0c;我感受到复用性的好处&am…

微信小程序:贪吃蛇

微信小程序&#xff1a;贪吃蛇 wx.js var startX 0; var startY 0; var moveX 0; var moveY 0; //移动位置和开始位置的坐标差值 var X 0; var Y 0; //蛇的对象 var snake {x: 0,y: 0,color: "#ff0000", w: 20,h: 20, } //食物对象 var food {x: 0,y: 0,co…

贪吃蛇的小程序

1 创建项目 1.打开微信开发者工具如图所示的界面&#xff0c;点击“ 2.填写项目以后&#xff0c;点击确定即可。如图所示&#xff1a; 2 编程 1.编写index.wxml的代码如下&#xff1a; <view class"container"><canvas style"width:100%;height:1…

【Python游戏】贪吃蛇升级版——双人贪吃蛇小游戏 | 附带源码

前言 之前做过一个单人版的贪吃蛇&#xff0c;所以常常就是我只能看着别人玩&#xff0c;或者别人看着我玩&#xff0c;却没法两个人一起愉快地玩耍。 由此产生了做一个可以双人玩的贪吃蛇想法&#xff0c;并且从小时候一直到现在&#xff0c;之前python还没有那么火的时候&am…

html版贪吃蛇

<!doctype html><html><head></head><body> <div id"box" style"width:256px;font:25px/25px 宋体;background:#000;color:#9f9;"></div><script> var arr[15]; var next10;//最好判断一下arr[1]!arr[0]x…

贪吃蛇智能版(高级)

说明&#xff1a; 在贪吃蛇智能版&#xff08;中级&#xff09;的基础之上&#xff0c;增加了判断小食物是否安全的方法&#xff0c;并且增加了在寻找食物路径失败和寻找尾巴失败之后&#xff0c;会进行一小段的随机溜达&#xff0c;直到重新找到路径为止&#xff0c;当然这段…

贪吃蛇微信小程序源码

每日分享两个小程序源码 下载地址&#xff1a;无极低码&#xff1a;wheart.cnhttps://wheart.cn/so/home?mdw&ridf6d836c8-d54a-11ed-96fa-52540016e6ac <!--snake.wxml--> <view class"control" bindtouchstart"tapStart" bindtouchmove&qu…

win10系统激活提示无法连接到你组织的激活服务器如何解决

1、在桌面新建一个文本文档&#xff0c;把以下代码复制进去&#xff0c;如图所示&#xff1a; slmgr /ipk W269N-WFGWX-YVC9B-4J6C9-T83GX slmgr /skms kms.03k.org slmgr /ato 2、点击文件选择“另存为”&#xff0c;在弹出的界面中&#xff0c;将保存位置选择在桌面&#xff…