iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >MyBatis中怎么查询千万数据量
  • 502
分享到

MyBatis中怎么查询千万数据量

2024-04-02 19:04:59 502人浏览 八月长安
摘要

这期内容当中小编将会给大家带来有关mybatis中怎么查询千万数据量,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。常规查询默认情况下,完整的检索结果集会将其存储在内存中。

这期内容当中小编将会给大家带来有关mybatis中怎么查询千万数据量,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

常规查询

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

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

@SneakyThrows @Override public void pageQuery() {     @Cleanup Connection conn = dataSource.getConnection();     @Cleanup Statement stmt = conn.createStatement();     long start = System.currentTimeMillis();     long offset = 0;     int size = 100;     while (true) {         String sql = String.fORMat("SELECT COLUMN_A, COLUMN_B, COLUMN_C FROM YOU_TABLE LIMIT %s, %s", offset, size);         @Cleanup ResultSet rs = stmt.executeQuery(sql);         long count = loopResultSet(rs);         if (count == 0) break;         offset += size;     }      log.info("  ??? 分页查询耗时 :: {} ", System.currentTimeMillis() - start); }

上述方式比较简单,但是在不考虑 LIMIT 深分页优化情况下,线上数据库服务器就凉了,亦或者你能等个几天时间检索数据

流式查询

如果你正在使用具有大量数据行的 ResultSet,并且无法在 JVM 中为其分配所需的内存堆空间,则可以告诉驱动程序从结果流中返回一行

MyBatis中怎么查询千万数据量

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

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

@SneakyThrows public void streaMQuery() {     @Cleanup Connection conn = dataSource.getConnection();     @Cleanup Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     stmt.setFetchSize(Integer.MIN_VALUE);     long start = System.currentTimeMillis();     @Cleanup ResultSet rs = stmt.executeQuery("SELECT COLUMN_A, COLUMN_B, COLUMN_C FROM YOU_TABLE");     loopResultSet(rs);     log.info("  ??? 流式查询耗时 :: {} ", (System.currentTimeMillis() - start) / 1000); }

流式查询库表数据量 500w 单次调用时间消耗:≈ 6s

游标查询

SpringBoot 2.x 版本默认连接池为 HikariPool,连接对象是  HikariProxyConnection,所以下述设置游标方式就不可行了

((JDBC4Connection) conn).setUseCursorFetch(true);

需要在数据库连接信息里拼接 &useCursorFetch=true。其次设置 Statement 每次读取数据数量,比如一次读取  1000

@SneakyThrows public void cursorQuery() {     @Cleanup Connection conn = dataSource.getConnection();     @Cleanup Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     stmt.setFetchSize(1000);      long start = System.currentTimeMillis();     @Cleanup ResultSet rs = stmt.executeQuery("SELECT COLUMN_A, COLUMN_B, COLUMN_C FROM YOU_TABLE");     loopResultSet(rs);     log.info("  ??? 游标查询耗时 :: {} ", (System.currentTimeMillis() - start) / 1000); }

游标查询库表数据量 500w 单次调用时间消耗:≈ 18s

JDBC RowData

上面都使用到了方法 loopResultSet,方法内部只是进行了 while 循环,常规、流式、游标查询的核心点在于 next 方法

@SneakyThrows private Long loopResultSet(ResultSet rs) {     while (rs.next()) {     // 业务操作     }     return xx; }

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

MyBatis中怎么查询千万数据量

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

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

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. 首先会查看自己内部缓冲区是否有数据没有返回,如果有则返回下一行

  3. 如果都读取完毕,向 MySQL Server 触发一个新的请求读取 fetchSize 数量结果

  4. 并将返回结果缓冲到内部缓冲区,然后返回第一行数据

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

总结来说就是,默认的 RowDataStatic 读取全部数据到客户端内存中,也就是我们的 JVM;RowDataCursor 一次读取  fetchSize 行,消费完成再发起请求调用;RowDataDynamic 每次 IO 调用读取一条数据

JDBC 通信原理

普通查询

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

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

普通查询的方式在查询大数据量时,所在 JVM 可能会凉凉,原因如下:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. MySQL Server 会将检索出的 SQL 结果集通过输出流写入到内核对应的 Socket Buffer

  3. 内核缓冲区通过 JDBC 发起的 tcp 链路进行回传数据,此时数据会先进入 JDBC 客户端所在内核缓冲区

  4. JDBC 发起 SQL 操作后,程序会被阻塞在输入流的 read 操作上,当缓冲区有数据时,程序会被唤醒进而将缓冲区数据读取到 JVM 内存中

  5. MySQL Server 会不断发送数据,JDBC 不断读取缓冲区数据到 Java 内存中,虽然此时数据已到 JDBC 所在程序本地,但是 JDBC  还没有对 execute 方法调用处进行响应,因为需要等到对应数据读取完毕才会返回

  6. 弊端就显而易见了,如果查询数据量过大,会不断经历 GC,然后就是内存溢出

游标查询

通过上文得知,游标可以解决普通查询大数据量的内存溢出问题,但是

小伙伴有没有思考过这么一个问题,MySQL 不知道客户端程序何时消费完成,此时另一连接对该表造成 DML 写入操作应该如何处理?

其实,在我们使用游标查询时,MySQL 需要建立一个临时空间来存放需要被读取的数据,所以不会和 DML 写入操作产生冲突

但是游标查询会引发以下现象:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. IOPS 飙升,因为需要返回的数据需要写入到临时空间中,存在大量的 IO 读取和写入,此流程可能会引起其它业务的写入抖动

  3. 磁盘空间飙升,因为写入临时空间的数据是在原表之外的,如果表数据过大,极端情况下可能会导致数据库磁盘写满,这时网络输出时没有变化的。而写入临时空间的数据会在  读取完成或客户端发起 ResultSet#close 操作时由 MySQL 回收

  4. 客户端 JDBC 发起 SQL 查询,可能会有长时间等待 SQL 响应,这段时间为服务端准备数据阶段。但是  普通查询等待时间与游标查询等待时间原理上是不一致的,前者是一致在读取网络缓冲区的数据,没有响应到业务层面;后者是 MySQL 在准备临时数据空间,没有响应到  JDBC

  5. 数据准备完成后,进行到传输数据阶段,网络响应开始飙升,IOPS 由"读写"转变为"读取"

采用游标查询的方式 通信效率比较低,因为客户端消费完 fetchSize 行数据,就需要发起请求到服务端请求,在数据库前期准备阶段 IOPS  会非常高,占用大量的磁盘空间以及性能

流式查询

当客户端与 MySQL Server 端建立起连接并且交互查询时,MySQL Server 会通过输出流将 SQL 结果集返回输出,也就是  向本地的内核对应的 Socket Buffer 中写入数据,然后将内核中的数据通过 TCP 链路回传数据到 JDBC 对应的服务器内核缓冲区

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. JDBC 通过输入流 read 方法去读取内核缓冲区数据,因为开启了流式读取,每次业务程序接收到的数据只有一条

  3. MySQL 服务端会向 JDBC 代表的客户端内核源源不断的输送数据,直到客户端请求 Socket 缓冲区满,这时的 MySQL 服务端会阻塞

  4. 对于 JDBC 客户端而言,数据每次读取都是从本机器的内核缓冲区,所以性能会更快一些,一般情况不必担心本机内核无数据消费(除非 MySQL  服务端传递来的数据,在客户端不做任何业务逻辑,拿到数据直接放弃,会发生客户端消费比服务端超前的情况)

看起来,流式要比游标的方式更好一些,但是事情往往不像表面上那么简单

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. 相对于游标查询,流式对数据库的影响时间要更长一些

  3. 另外流式查询依赖网络,导致网络拥塞可能性较大

流式游标内存分析

表数据量:500w

内存查看工具jdk 自带 Jvisualvm

设置 JVM 参数:-Xmx512m -Xms512m

单次调用内存使用

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

MyBatis中怎么查询千万数据量

图1 数据仅供参考

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

MyBatis中怎么查询千万数据量

图2 数据仅供参考

根据内存占用情况来看,游标查询和流式查询都 能够很好的防止 OOM

并发调用内存使用

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

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

MyBatis中怎么查询千万数据量

图3 数据仅供参考

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

流式查询并发调用时间平均消耗:≈ 55s

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

MyBatis中怎么查询千万数据量

图4 数据仅供参考

游标查询并发调用时间平均消耗:≈ 83s

因为设备限制,以及部分情况只会在极端下产生,所以没有进行生产、测试多环境验证,小伙伴感兴趣可以自行测试

MyBatis 如何使用流式查询

上文都是在描述如何使用 JDBC 原生 api 进行查询,ORM 框架 Mybatis 也针对流式查询进行了封装

ResultHandler 接口只包含 handleResult 方法,可以获取到已转换后的 Java 实体类

@Slf4j @Service public class MyBatisStreamService {     @Resource     private MyBatisStreamMapper myBatisStreamMapper;      public void mybatisStreamQuery() {         long start = System.currentTimeMillis();         myBatisStreamMapper.mybatisStreamQuery(new ResultHandler<YOU_TABLE_DO>() {             @Override             public void handleResult(ResultContext<? extends YOU_TABLE_DO> resultContext) { }         });         log.info("  ??? MyBatis查询耗时 :: {} ", System.currentTimeMillis() - start);     } }

除了下述注解式的应用方式,也可以使用 .xml 文件的形式

@Mapper public interface MyBatisStreamMapper {     @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE)     @ResultType(YOU_TABLE_DO.class)     @Select("SELECT COLUMN_A, COLUMN_B, COLUMN_C FROM YOU_TABLE")     void mybatisStreamQuery(ResultHandler<YOU_TABLE_DO> handler); }

Mybatis 流式查询调用时间消耗:&asymp; 18s

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. JDBC 流式与 MyBatis 封装的流式读取对比

  3. MyBatis 相对于原生的流式还是慢上了不少,但是考虑到底层的封装的特性,这点性能还是可以接受的

  4. 从内存占比而言,两者波动相差无几

MyBatis 相对于原生 JDBC 更为的方便,因为封装了回调函数以及序列化对象等特性

上述就是小编为大家分享的MyBatis中怎么查询千万数据量了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网数据库频道。

您可能感兴趣的文档:

--结束END--

本文标题: MyBatis中怎么查询千万数据量

本文链接: https://www.lsjlt.com/news/57844.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • MyBatis中怎么查询千万数据量
    这期内容当中小编将会给大家带来有关MyBatis中怎么查询千万数据量,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。常规查询默认情况下,完整的检索结果集会将其存储在内存中。...
    99+
    2022-10-18
  • oracle千万级数据怎么查询
    查询千万级数据可以采用以下方法:1. 使用索引:对于经常需要查询的字段,可以创建索引来加快查询速度。索引可以提高查询性能,但会增加写...
    99+
    2023-09-13
    oracle
  • Mysql中千万数据查询浅析
    假如mysql数据库中有一千万数据,如何进行查询,查询效率如何,下面进行简单的分析。 1、准备数据 也许有些人没遇见过上千万数据量的表,没关系,下面通过sql脚本准备一下数据,环境为:mysql...
    99+
    2023-09-15
    mysql 数据库 千万条数据
  • Mysql中一千万条数据怎么快速查询
    目录普通分页查询如何优化偏移量大采用id限定方式优化数据量大问题普通分页查询 当我们在日常工作中遇到大数据查询的时候,第一反应就是使用分页查询。 mysql支持limit语句来选取...
    99+
    2022-11-12
  • 怎么在一个千万级的数据库查询中提高查询的效率
    小编给大家分享一下怎么在一个千万级的数据库查询中提高查询的效率,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在实际项目中,当数据...
    99+
    2022-10-18
  • mysql怎么批量更新千万数据
    批量更新千万条数据可以使用MySQL的UPDATE语句结合WHERE子句来实现。下面是一个示例: UPDATE 表名 SET...
    99+
    2023-10-24
    mysql
  • 怎么样优化mysql千万级数据分页查询性能
    本文主要给大家简单讲讲怎么样优化mysql千万级数据分页查询性能,相关专业术语大家可以上网查查或者找一些相关书籍补充一下,这里就不涉猎了,我们就直奔主题吧,希望怎么样优化mysql千万级数据分页查询性能这篇...
    99+
    2022-10-18
  • 详解MySQL数据库千万级数据查询和存储
    目录百万级数据处理方案数据存储结构设计查询语句优化千万级数据处理方案数据存储结构设计数据库表主键设计MySQL面试题MySQL数据库千万级数据查询优化方案你用过MySQL那些存储引擎他们都有什么特点和区别?那他们都有...
    99+
    2022-05-14
    mysql 数据 mysql 存储 千万级 优化
  • Oracle中怎么插入与查询千万条记录
    本篇文章给大家分享的是有关Oracle中怎么插入与查询千万条记录,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1、 避免使用Hibernate...
    99+
    2022-10-18
  • mysql千万级数据量根据索引优化查询速度的实现
    (一)索引的作用 索引通俗来讲就相当于书的目录,当我们根据条件查询的时候,没有索引,便需要全表扫描,数据量少还可以,一旦数据量超过百万甚至千万,一条查询sql执行往往需要几十秒甚至更...
    99+
    2022-11-11
  • MySQL千万级数据查询的优化技巧及思路
    随着数据量的不断增长,MySQL千万级数据查询的优化问题也日益引人注目。在这篇文章中,我们将深入探讨MySQL千万级数据查询优化的方法和技巧,以帮助开发者更好地优化MySQL性能。 一、数据库设计 数据库设计是优化查询性能的关键,以下是一些...
    99+
    2023-09-03
    数据库 mysql java
  • mysql千万级别的数据使用count(*)查询比较慢怎么解决?
    当MySQL中的数据量达到千万级别时,使用COUNT()查询可能会变得比较慢。这是因为COUNT()会扫描整个表并计算匹配的行数,对于大表来说,这个过程可能会非常耗时。 在上图中查询一千三百多万...
    99+
    2023-09-24
    mysql 数据库 mysql千万级别数据
  • MySQL数据库千万级数据查询和存储的示例分析
    这篇文章主要介绍MySQL数据库千万级数据查询和存储的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!百万级数据处理方案数据存储结构设计表字段设计表字段 not null,因为 null 值很难查询优化且占用额...
    99+
    2023-06-15
  • 在一个千万级的数据库查寻中,如何提高查询效率????
    摸清数据产生量如何,如果是1钞钟1条记录,则一台车一天就有86400条记录,则建议如下: 每台车使用单独的表,程序内部使用CreateTable,动态创建表,销毁表。这样车与车之间不会产生联系。 前提:系统管理的车应该不会经常变...
    99+
    2014-10-15
    在一个千万级的数据库查寻中,如何提高查询效率????
  • springbatch怎么处理千万级数据
    处理千万级数据的方法可以通过以下步骤实现:1. 分批读取数据:使用Spring Batch的chunk机制,将数据分批读取到内存中。...
    99+
    2023-08-18
    springbatch
  • MySQL中怎么优化千万级数据表
    MySQL中怎么优化千万级数据表,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。我这里有张表,数据有1000w,目前只有一个主键索引CREATE TAB...
    99+
    2023-06-20
  • 30个mysql千万级大数据SQL查询优化技巧详解
    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导...
    99+
    2022-10-18
  • MySQL千万级大数据SQL查询优化知识点有哪些
    这篇文章给大家分享的是有关MySQL千万级大数据SQL查询优化知识点有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 wh...
    99+
    2022-10-18
  • 怎么在MySql中插入千万级大数据
    今天就跟大家聊聊有关怎么在MySql中插入千万级大数据,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。第一步,读取文件,开始插入多线程在这里,达到一定...
    99+
    2022-10-18
  • Mybatis游标查询大量数据方式
    目录Mybatis游标查询大量数据mapper层service层 资源释放Mybatis游标使用总结什么是游标Mybatis游标查询大量数据 对大量数据进行处理时,为防止内...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作