【数据库】聊聊数据库中的 fetchsize 参数

news2024/11/28 14:48:15

聊聊数据库中的 fetchsize 参数

  • 1.介绍
  • 2.案例
  • 3.MySQL 中的 fetchsize
  • 4.Oracle 中的 fetchsize

1.介绍

在使用查询语句的时候,经常需要根据条件来进行查询得到最终的总记录条数,然后得到结果之后需要来进行处理。

场景:Java 端从数据库读取 100W 数据进行后台业务处理。

  • 常规实现 1:分页读取出来。缺点:需要排序后分页读取,性能低下。
  • 常规实现 2:一次性读取出来。缺点:需要很大内存,一般计算机不行。
  • 非常规实现:建立长连接,利用服务端游标,一条一条流式返回给 Java 端。
  • 非常规实现优化:JDBC 中有个重要的参数 fetchSize(它对业务实现无影响,即不会限制读取条数等),优化后可显著提升性能。

缺省时,驱动程序一次从查询里获取所有的结果。这样可能对于大的数据集来说是不方便的, 因此 JDBC 驱动提供了一个用于设置从一个数据库游标抽取若干行的 ResultSet 的方法。在连接的客户端这边缓冲了一小部分数据行,并且在用尽之后, 则通过重定位游标检索下一个数据行块。

setFetchSize 最主要是为了减少网络交互次数设计的。访问 ResultSet 时,如果它每次只从服务器上取一行数据,则会产生大量的开销。setFetchSize 的意思是当调用 rs.next 时,ResultSet 会一次性从服务器上取得多少行数据回来,这样在下次 rs.next 时,它可以直接从内存中获取出数据而不需要网络交互,提高了效率。 这个设置可能会被某些 JDBC 驱动忽略的,而且设置过大也会造成内存的上升。

2.案例

MySQL 中的 fetchsize 是指从结果集中获取行数据的大小。fetchsize 的大小直接影响到程序的性能和响应时间,因此是值得注意的。

在 MySQL 中,当执行 SELECT 语句时,会返回一定数量的数据行。fetchsize 就是表示从结果集中获取多少行数据的大小。

int fetchSize = 100;  //设置fetchsize的大小为100
Statement stmt = conn.createStatement();
stmt.setFetchSize(fetchSize); //将fetchsize的大小设置为100
ResultSet rs = stmt.executeQuery("SELECT * FROM users");

上面的代码中,fetchsize 的大小被设置为 100。当 ResultSet 对象被创建后,只会获取到前 100 条数据。当我们遍历 ResultSet 对象时,例如使用 rs.next(),在获取到第 100 条记录时,会自动从数据库中获取接下来的数据。由此,我们可以看出,fetchsize 对程序的性能和响应时间起到非常重要的作用。

fetchsize 设置的太小,会导致程序频繁地访问数据库,从而影响程序的性能;当 fetchsize 设置的太大,可能会导致内存不足,从而影响程序的响应时间。

因此,在设置 fetchsize 时,需要结合程序的具体需求和硬件设备的配置进行合理的调整。如果不确定 fetchsize 的大小该如何设置,可以先进行测试,不断调整 fetchsize 的大小,直到找到合适的配置。

3.MySQL 中的 fetchsize

默认情况下,MySQL 的 JDBC 驱动会一下子把所有 row 都读取下来,这在一般情况下是最优的,因为可以减少 Client - Server 的通信开销。但是这样也有一个问题,当数据库查询结果很大时,特别当不能全部放进内存时,就会产生性能问题。 本来,JDBC API 里在 Connection、Statement 和 ResultSet 上都有设置 fetchSize 的方法, 但是 MySQL 的 JDBC 驱动都不支持,无论你怎么设 fetchSize,ResultSet 都会一次性从 Server 读取数据。在 MySQL 的官方论坛上也有多个这样的问题,总结一下解决办法如下:

  • MySQL 版本在 5.0 以上,MySQL 的 JDBC 驱动更新到最新版本(至少 5.0 以上)
  • Statement 一定是 TYPE_FORWARD_ONLY 的,并发级别是 CONCUR_READ_ONLY(即创建 Statement 的默认参数)
  • 以下两句语句选一即可:
    • statement.setFetchSize(Integer.MIN_VALUE);
    • ((com.mysql.jdbc.Statement)stat).enableStreamingResults();

这样会一行一行地从 Server 读取数据,因此通信开销很大,但内存问题可以解决。官方的说法是不支持 fetchSize 不是 MySQL 的 JDBC 驱动的问题,而是 MySQL 本身就不支持。而商用数据库 Oracle 或 DB2 都是支持 fetchSize 的,从这里也可以看出两者的考量不同。

MySQL 默认是不支持 fetchSize 的,像 Oracle 和 DB2 等商业数据库则支持,那么这么在 JDBC 连接 MySQL 是使用这个参数呢,满足三个条件,,官方是这么说的

param
explain
value
useCursorFetchIf connected to MySQL > 5.0.2, and setFetchSize() > 0 on a statement, should that statement use cursor-based fetching to retrieve rows?false
  • 首先数据库版本要高于 5.0.2
  • 再就是设置了 fetchSize
  • 最最重要的是在数据库连接后加上,useCursorFetch=true
url=jdbc:mysql://192.168.1.3:3306/cuishou3?useCursorFetch=true

4.Oracle 中的 fetchsize

上面已经讲过了 Oracle 是默认支持的。

public static void main(String[] args) throws SQLException {
    getAll(1);
    getAll(10);
    getAll(100);
    getAll(1000);
}

public static void getAll(int fetchSize) {
    try {
        long beginTime = System.currentTimeMillis();

        Connection connection = DriverManager.getConnection(MYSQL_URL);
        connection.setAutoCommit(false); //为了设置fetchSize,必须设置为false
        String sql = "select * from test";
        PreparedStatement psst = connection.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
        psst.setFetchSize(fetchSize);
        ResultSet rs = psst.executeQuery();

        int totalCount = 0;
        // 从内存中来进行读取
        while (rs.next()) {
                totalCount++;
        }
        rs.close();
        psst.close();
        connection.close();

        long endTime = System.currentTimeMillis();
        System.out.println("totalCount:"+totalCount+";fetchSize:"+fetchSize+";耗时:"+(endTime-beginTime)+"ms");
    } catch (SQLException e) {
        e.printStackTrace();
    } 
}

执行结果如下所示:

totalCount:3185194;fetchSize:1;耗时:23770ms
totalCount:3185194;fetchSize:10;耗时:23253ms
totalCount:3185194;fetchSize:100;耗时:21890ms
totalCount:3185194;fetchSize:1000;耗时:20985ms

可以看到,当 fetchSize 为 1000 时,性能有提升(看一些网友的数据,性能提升更多)。

  • 先在服务端执行查询后将数据缓存在服务端(耗时相对较长)。
  • Java 端获取数据时,利用服务端游标进行指针跳动,如果 fetchSize 为 1000,则一次性跳动 1000 条,返回给 Java 端缓存起来(耗时较短,跳动次数为 N / 1000 N/1000 N/1000)。
  • 在调用 next 函数时,优先从缓存中取数,其次执行上一步过程(内存读取,耗时可忽略)。

在这里插入图片描述

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

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

相关文章

【数据结构与算法】之数组系列-20240117

这里写目录标题 一、167. 两数之和 II - 输入有序数组二、164. 最大间距三、128. 最长连续序列四、122. 买卖股票的最佳时机 II五、78. 子集六、75. 颜色分类 一、167. 两数之和 II - 输入有序数组 中等 给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递…

【python】基础知识类的语法功能讲解

Python代码定义了一个名为Calculation的类,用于执行基础的数学运算(加法、减法、乘法、除法和取模)。下面我将详细解释各个部分的功能,并以列表形式总结: 类定义: class Calculation: 定义了一个名为Cal…

Simulink|双机并联自适应虚拟阻抗下垂控制仿真模型

目录 主要内容 模型研究 结果一览 下载链接 主要内容 风电高渗透率下,电力系统对风电场频率调节能力提出了技术要求。考虑风机惯性控制和变桨距控制的频率响应能力,提出将储能与风电自身调频手段相结合,参与系统频率调节。模型…

JSP简单学习

jsp是在html中嵌入java代码 jsp也是在j2ee服务端中的java组件 第一次运行 在第一次运行jsp代码时会经历以下步骤,将jsp转为java代码,将java代码转为class文件。 所以通常会比较慢,编译后就好多了。 四大作用域 requestsessionpageapplica…

25考研英语复习计划

Hello各位小伙伴大家好,今天要给大家分享的是英语备考计划,大家可以作为参考,制定适合自己的备考计划。 【英一/二】 英语分为英一、英二,一般学硕英一,专硕英二。 英一要比英二难度大。 【复习计划】 1-2月&#xf…

python - 无法正常显示xlabel / ylabel

python 无法正常显示xlabel / ylabel 如上述所示, 第一个子图是不带投影的,可以正常显示横纵轴标签和标题第二个子图带有投影,横纵轴通过手动设置范围,可以正常显示横纵轴标签和标题第三个子图带有投影,横纵轴的tick …

基于LDA的评论大数据的分析及主题建模

1.微博的关键词大数据采集; 已完成,待优化 2.LDA 错误1:使用了import pyLDAvis.sklearn,提示没有模块no module named pyldavis.sklearn。 默认安装 pyLDAvis3.4.1,最后降级处理,解决方式: …

Java精品项目源码springboot面向社区养老服务的应用系统(编号V71)

Java精品项目源码springboot面向社区养老服务的应用系统(编号V71) 大家好,小辰今天给大家介绍一个面向社区养老服务的应用系统,演示视频公众号(小辰哥的Java)对号查询观看即可 文章目录 Java精品项目源码springboot面向社区养老…

pve虚拟机的改名和修改ID

PVE的虚拟机名字在web界面是无法修改id和名字的。要注意id和名字不能重。 在使用备份时就发现虚拟机是以虚拟机id作为唯一标识,如果有多台pve节点,但共用同一个nfs目录备份或使用同一个pbs进行备份时就必须保障id的唯一性。这时可以使用这个方法来进行补…

maven无法识别本地maven仓库包解决方案

前言:由于本地maven仓库已经有了相关依赖包,idea还是去远程仓库下载(不知何原因,生产上到远程仓库的网络突然不通了),故需要自己本地上传相关包到生产主机并修改setttings文件来强制读取本地仓库方案 settings文件修改如下方式即…

【Gradle】Maven-Publishing

使用Java开发完成一个模块或者一个基础框架需要提供给团队项目使用,这个时候有两种方式可提供,一是提供源码,二是提供编译构建好的jar包供使用,这个时候需要讲构建好的包发布到公司的私服(公司maven仓库)&a…

最新版git2.43安装、记住用户名和密码以及tortoisegit2.15使用

一、下载git 打开git官网地址:https://git-scm.com/进行下载 下载完安装,一直next就好,如果愿意就可以改下安装路径,改在d盘。 具体可以参考:git安装教程 二、安装完下载小乌龟以及中文语言包 下载地址:…

SQL性能分析

SQL性能分析 1、SQL执行频率 ​ MySQL 客户端连接成功后,通过 show [session|global] status 命令可以提供服务器状态信 息。通过如下指令,可以查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次: -- session 是查看当前会话 ; …

【Maven】009-Maven 简单父子工程搭建

【Maven】009-Maven 简单父子工程搭建 文章目录 【Maven】009-Maven 简单父子工程搭建一、需求说明1、结构2、第三方库 二、工程搭建1、父工程第一步:创建父工程第二步:引入公共依赖 lombok 和管理 hutool 依赖版本 2、公共子模块第一步:创建…

越来越多的人学习PMP,2024年考PMP还有价值吗?

转管理是大部分人30人的想法,尤其是 IT行业有个 "35大关”考PMP的人是最多的。 “经验式管理终将成为过去,专业式管理才是时代趋势”,要想做好一个项目经理,系统的项目管理知识和项目经验缺一不可。经验是需要积累的&#x…

spring boot学习第七篇:通过spring boot使用redis

1、pom.xml文件里面增加如下依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 2、yml文件增加如下配置&#xff1a; redis:host: loc…

pytest -- 进阶使用详解

pytest-html⽣成报告 Pytest-HTML 是⼀个插件&#xff0c;它可以⽣成漂亮且易于阅读的 HTML 测试报告。 pytest-html ⽣成报告的步骤 ① 安装 pytest-html 插件&#xff1a; pip install pytest-html ② 运⾏测试并⽣成报告&#xff1a; file name:main.pyimport pytest&qu…

自动驾驶3.0时代,大模型将重塑竞争格局,谁将笑到最后?

“毫末DriveGPT发布200天左右的时间&#xff0c;已经完成了亿级公里量产驾驶数据训练&#xff0c;累积高达480万段Clips的高质量测试。” 在2023&#xff08;第七届&#xff09;高工智能汽车年会上&#xff0c;毫末智行上海研发中心负责人孙宣峰在发表《自动驾驶 3.0 时代&…

NAS入门(学习笔记)

文章目录 AutoMLNAS初期NAS当前NAS框架One-Shot NAS权重共享策略 Zero-Shot NASZen-NASNASWOTEPENAS 参考资料 AutoML 深度学习使特征学习自动化 AutoML 使深度学习自动化 自动化机器学习 (automated machine learning) 是一种自动化的数据驱动方法, 并做出一系列决策。 按…

Flutter 综述

Flutter 综述 1 介绍1.1 概述1.2 重要节点1.3 移动开发中三种跨平台框架技术对比1.4 flutter 技术栈1.5 IDE1.6 Dart 语言1.7 应用1.8 框架 2 Flutter的主要组成部分3 资料书籍 《Flutter实战第二版》Dart 语言官网Flutter中文开发者社区flutter 官网 4 搭建Flutter开发环境参考…