大数据量查询:流式查询与游标查询

这篇具有很好参考价值的文章主要介绍了大数据量查询:流式查询与游标查询。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        最近在做一个计算相关的功能,大体就是有很多条SQL,每条SQL都涉及复杂地运算,最后要将所有计算结果进行合并分析。经初步测试,每个SQL起码会查出几十万条记录,我们现在有毛毛多的这种SQL。

        最大的问题不在于速度,毕竟涉及运算的功能,想要从速度入手就得靠中间件和算法了。内存占用才是我们最需要注意的,一旦数据量很大且一次性冲入Java堆内存,程序会直接OOM然后离开人世。比如使用非分页的普通查询,这张表1000w条数据你有多少要多少,除非你设置-xms 128g,否则程序是一定会死的。

        当然平时我们一般都会指定分页参数,但遇到大数据量查询时,为了内存的身体健康,还是需要一些特殊的方式——流式查询与游标查询。

1 流式查询

       采用传统的Stream流式思想,将直接提供数据替换成提供获取数据的管道,客户端读取数据时直接从管道中遍历获取;整个读取的过程需要客户端保持和服务端的连接,也很好理解,它实际是一个管道,管道得通着才能取数据。

        流式查询有两种使用方式,一种是用Cursor<T>作为返回值,对数据进行遍历操作;一种是不设置返回值,在入参中传入一个ResultHandler<T>作为回调处理数据。本文将基于Mybatis具体介绍使用方法。

        这两种返回值的使用方式是相似的,唯一区别就是返回值不同。Mybatis查询有两种方式,一种是基于注解加在Mapper接口上方,一种是写在xml文件中,主要需要设置以下几个属性:

ResultSetType 结果集读取方式
FetchSize MySQL服务端单次发送至客户端的数据条数
ResultType 这个眼熟吧,设置返回实体类映射

        ResultType没什么好说的,一般Mybatis查询都会用到,我们着重介绍一下ResultSetType和FetchSize。ResultSetType有4种可选项,我们点进去看看,DEFAULT不谈,主要是下面三种。 

    DEFAULT(-1),
    FORWARD_ONLY(1003),
    SCROLL_INSENSITIVE(1004),
    SCROLL_SENSITIVE(1005);
  • FORWARD_ONLY,顾名思义只能向前,即数据只能向前读取,是不是就类似一个流水的管道,读一条就相当于水流过去一些。也是我们需要选用的。
  • SCROLL_INSENSITIVE,不敏感滚动,和下面那个差不多,都是可以向后读或向前读;这意味着已读取过的数据不能丢掉,要继续保存在内存中,因为有可能会回去再次读取他们。
  • SCROLL_SENSITIVE,敏感滚动,和上面那个差不多。

        这么一比较就看得出来,当选的一定是FORWARD_ONLY,我们亟需解决的就是大数据量对内存的影响,再用后面两个还是会放在内存中。

        再看FetchSize,这个概念在许多服务中都有提及,例如RabbitMQ中是消费者取过来预处理的消息数量,但在MySQL中完全不是一个概念。MySQL的数据传输是基于C/S的阻塞机制,即Client设置FetchSize = 1000,而Server查出来10000条数据,按照常理应该是Server智能地使用分页策略1000条1000条取;实际不是,Server查出来多少就是多少,他会放在自己特定的内存空间内,只是会根据FetchSize的大小一点一点传送给Client——利用C/S的通讯阻塞,发1000条、堵一下、发1000条、堵一下……。

        话又说回来,怎么配置这个FetchSize呢?JDBC官方给出的答案是设置为“Integer.MIN_VALUE”,具体原因不清楚,但我猜是为了和游标查询区分开,因为一会你会发现流式查询和游标查询唯一的区别就是FetchSize的大小。

        设置好这3个参数以后,就可以用Cursor或者ResultHandler来处理返回值了。有如下几种写法。

(1)注解式 

    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE)
    @ResultType(ResultVo.class)
    @Select("SELECT *, 0 orderType FROM `table`\n" +
            "        WHERE username = #{userName}")
    Cursor<ResultVo> listOrders(@Param("userName") String userName);

    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE)
    @ResultType(ResultVo.class)
    @Select("SELECT *, 0 orderType FROM `table`\n" +
            "        WHERE username = #{userName}")
    void listOrders2(@Param("userName") String userName, ResultHandler<ResultVo> handler);

        使用Mybatis的注解,在@Options中指定查询配置参数,在@ResultType中指定返回值类型 ,在@Select中指定查询语句。最后用Cursor接收返回值,Cursor是可遍历的,所以直接Foreach遍历即可;或者用ResultHandler处理数据回调,在调用方式时传入new ResultHandler并写明处理逻辑。

(2)xml方式

<select id="listOrders" resultType="com.vo.ResultVo" resultSetType="FORWARD_ONLY" fetchSize="-2147483648">
    SELECT *, 1 stuffCount, 1 orderType FROM `table`
    WHERE username = #{userName}
</select>

        本质是相同的,只不过是将注解中的内容放进了标签中,返回值和数据处理方式也一致。

        需要注意的是,不可以注解 + xml混合使用,比如注解指定fetchSize,xml只写查询语句,这种只有xml语句会生效!!!要不全用注解,要不全用xml!!! 

2 游标查询

        游标查询主要依靠FetchSize属性,指定Server每次传输给Client数据的条数。这种方式由于我没有实验就不卖弄了,使用方式和流式查询基本一致,只是FetchSize不能是Integer.MIN_VALUE,而是一个真实的数字,不能太大也不能太小,太大了内存受不了,太小了客户受不了。

        不过JDBC查询默认是不支持FetchSize属性的,需要在JDBC连接URL后面加上“useCursorFetch=true”。这就不是很理想了,你说你写个代码还要改数据库连接的属性,万一后面出任何查询上的问题,都有可能追溯到你头上,所以我没敢用游标查询。

3 注意点

        流式查询由于需要保持客户端与服务端的连接,而一般查询提交完连接就会关闭;因此我们需要保持事务开启,否则会报“A Cursor is already closed.”,即Cursor已经关闭,没法再读取了。最简单的方法就是在方法上加@Transactional,在查询完毕以前事务会一直持有这个数据库连接,但我们在使用完毕后也要自行关闭连接,显式调用Cursor.close(),或者用try with resource语句。

        还要知道如何判断自己是否使用了流式查询或游标查询,下面是几个数据集的对应关系:

查询方式 结果集类型 行数据类型
普通分页 ResultsetRowsStatic RowDataStatic
流式查询 ResultsetRowsStreaming RowDataDynamic
游标查询 ResultsetRowsCursor RowDataCursor

        我使用到的流式查询,debug到DefaultResultSetHandler.class中,显示rsw中确实存储了ResultSetRowsStreaming。

流式查询和游标查询,sql,数据库,spring cloud,spring boot,微服务

4 优劣分析

        这3种查询方式,常规非大数据模式下普通查询最快,其次是流式查询,最次是游标查询。

        主要是由于游标查询需要和数据库进行多次网络交互,Client处理完这部分后再拉取下一部分数据,因此会比较慢。但是流式查询又会长时间占用同一个数据库连接,因此要取舍一下是能接受连接一直持有但是可能会堵住导致响应慢,还是可能占用较多连接数但单次响应快。文章来源地址https://www.toymoban.com/news/detail-615568.html

到了这里,关于大数据量查询:流式查询与游标查询的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 关系数据库SQL数据查询

    1.查询仅涉及一个表,选择表中的若干列 查询全部列 选出所有属性列: 在SELECT后面列出所有列名 将目标列表达式指定为 * 查询经过计算的值 SELECT子句的目标列表达式不仅可以为表中的属性列,也可以是表达式 使用列别名改变查询结果的列标题: 2.选择表中的若干元组

    2024年02月09日
    浏览(55)
  • 数据库作业-sql语句查询

    建表的插入数据的表 数据库作业-sql建表和插入数据_快乐的xiao何的博客-CSDN博客 create table supplier( supplierno char(6) primary key, suppliername nvarchar(10), address nvarchar(20), number char(11) )create table category( categoryno char(5) primary key, categoryname varchar(20), descriptions text... https://blog.csdn.net/m0_539670

    2023年04月23日
    浏览(57)
  • 数据库SQL查询相关练习

    1、显示所有职工的基本信息。 2、查询所有职工所属部门的部门号,不显示重复的部门号。 3、求出所有职工的人数。 4、列出最高工和最低工资。 5、列出职工的平均工资和总工资。 6、创建一个只有职工号、姓名和参加工作的新表,名为工作日期表。 8、列出所有姓刘的职工

    2024年01月25日
    浏览(49)
  • 【数据库】日常使用PL/SQL 登录ORACLE 数据库查询数据

    一、PL/SQL 登录方式 username: ##访问数据库的账号 password: ##访问数据库的密码 Databse: ##数据库IP地址/实例名 数据库集群心跳地址/实例名 Connect as : ##Normal,如果使用sysdba账户登录选择SYSDBA 二、PL/SQL使用SQL语句查询 点击上方导航栏,New,选择SQL Window,即可再次输入要查询的

    2024年02月19日
    浏览(70)
  • 数据库 SQL高级查询语句:聚合查询,多表查询,连接查询

    创建Students和Courses表 直接查询 设置别名查询 设置条件查询 使用COUNT(*) 和 COUNT(StudentID)是一样的效果,因为StudentID是主键,每行记录的主键都不同。另外我们在聚合查询中还是能使用WHERE子句的,比如我们要 查找年龄大于20岁的学生数量 ,可使用以下SQL语句: 函数 说明 SUM

    2024年02月09日
    浏览(127)
  • 《数据库原理》实验六 SQL数据查询实验

    本系列传送门: 实验二 SQL Server SSMS工具创建和管理数据库及数据表 实验三 SQL Server SSMS工具添加数据 实验四 SQL的数据定义语句 实验五 数据库完整性约束的实现与验证 实验六 SQL数据查询实验 实验六(2) SQL数据查询—连接查询 实验七 SQL的数据更新和视图 实验八 T_SQL编程

    2024年02月03日
    浏览(102)
  • SQL Server数据库 -- 表的高级查询

      一、子查询 嵌套子查询 相关子查询 二、查询运算 并运算union 交运算intersect 差运算except 三、函数的使用 if语句 while语句 case语句 四、总结 高级子查询是对查询更灵活的运用,学会了高级查询将对数据库使用有很大的帮助。       在SQL语言中,一个select-from-where语句称为一

    2024年02月13日
    浏览(58)
  • SQL数据库的查询操作大全(select)

    1、数据库的连接、创建 2、对字段的操作:(alter table) 3、对数据的操作(插入、修改、删除) 4、数据查询(select) 5、多表查询(join on) 6、约束操作 四、数据库查询大全(select) 1、select 字段名 from 表; 2、In查询:用于 过滤 你所需要查询的内容                

    2023年04月08日
    浏览(73)
  • WordPress必备数据库SQL查询语句整理

    最近明月给博客和主站都部署了SSL证书,彻彻底底的加入了HTTPS站点行列。这个期间也用到了SQL查询语句来批量的对内链的HTTP前缀做替换,就感觉掌握一些SQL方面的语句还是非常有必要的,这不在【俄语译客】博客上就发现了几条比较实用的,适合 WordPress 实用的SQL语句。于

    2024年02月01日
    浏览(103)
  • SQL Server数据库 -- 表的基础查询

    一、单表查询基本结构 二、单表查询结构语法 select 聚合函数 where 模糊查询 order by group by having 三、多表查询基本结构 四、多表查询结构语法 内连接 自连接 外连接 五、总结         学习了数据库,在以后公司等地方,你可能不会用到创建数据库或者表格,但是你一定会使

    2024年02月11日
    浏览(96)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包