您的当前位置:首页正文

JDBC批量读取优化-fetchSize

2023-11-13 来源:要发发知识网
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;耗时:23770mstotalCount:3185194;fetchSize:10;耗时:23253mstotalCount:3185194;fetchSize:100;耗时:21890mstotalCount:3185194;fetchSize:1000;耗时:20985ms

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

 

(三)原理分析

1、先在服务端执行查询后将数据缓存在服务端。(耗时相对较长)

2、java端获取数据时,利用服务端游标进行指针跳动,如果fetchSize为1000,则一次性跳动1000条,返回给java端缓存起来。(耗时较短,跳动次数为N/1000)

3、在调用next函数时,优先从缓存中取数,其次执行2过程。(内存读取,耗时可忽略)

技术图片

题外话:spring的JdbcCursorItemReader是对fetchSize的良好应用。

 

JDBC批量读取优化-fetchSize

标签:red   resultset   etc   exce   toc   begin   res   服务   rest   

小编还为您整理了以下内容,可能对您也有帮助:

mybatis大数据查询优化:fetchSize

这两天做到一个需求,需要一次性将一张数据表里的所有资源数据中的位置信息录入到redis中,表中的数据有几百万起步,采用的是java定时任务,循环每次查出一万条数据存入redis,测试时发现插入效率非常慢,经过排查发现是通过mybatis查询数据的耗时超过了总耗时的99%,我这台机器上是每查询一万条数据返回耗时87s左右。
解决方法:
在mapper.xml中的<select>中加入fetchSize参数,设置的大一些,如下:

我也是第一次用这个参数,这效果,感觉非常神奇!

简单参数解析:
通过JDBC取数据时,默认是10条数据取一次,即fetch size为10(根据oracle的文档,默认的fetchSize是10),如果增大这个数字可以减少客户端与oracle的往返,减少响应时间,网上有建议这个数字不要超过100,要不然对中间件内存消耗大。
虽然说超过100不好,但是我设置了10000,结果看我的破电脑还是扛得住的,但是本着专研精神,我将fatch size设置为1000,看看效果会不会打折扣,结果用时如下:

总结:
在使用mybatis一次查询大量数据时确实可以通过怎大fatchSize的值来大大提高查询效率,使用也非常简单,具体fatchSize设为多少要根据自己具体的业务需要和机器的配置来综合判定。

待解决问题
以上方式在xml中可以轻松设置,但是使用mybatis-plus的简单查询时并不用手动写xml查询,我也不知道如何定制其fatchSize的值,我目前的解决方式是手动在xml中再写一个查询方法来调用,但是感觉这样做非常的麻烦,如果你知道如何在调用mybatis-plus的BaseMapper查询方法时配置fatchSize,请留言告知,十分感谢!

mybatis大数据查询优化:fetchSize

这两天做到一个需求,需要一次性将一张数据表里的所有资源数据中的位置信息录入到redis中,表中的数据有几百万起步,采用的是java定时任务,循环每次查出一万条数据存入redis,测试时发现插入效率非常慢,经过排查发现是通过mybatis查询数据的耗时超过了总耗时的99%,我这台机器上是每查询一万条数据返回耗时87s左右。
解决方法:
在mapper.xml中的<select>中加入fetchSize参数,设置的大一些,如下:

我也是第一次用这个参数,这效果,感觉非常神奇!

简单参数解析:
通过JDBC取数据时,默认是10条数据取一次,即fetch size为10(根据oracle的文档,默认的fetchSize是10),如果增大这个数字可以减少客户端与oracle的往返,减少响应时间,网上有建议这个数字不要超过100,要不然对中间件内存消耗大。
虽然说超过100不好,但是我设置了10000,结果看我的破电脑还是扛得住的,但是本着专研精神,我将fatch size设置为1000,看看效果会不会打折扣,结果用时如下:

总结:
在使用mybatis一次查询大量数据时确实可以通过怎大fatchSize的值来大大提高查询效率,使用也非常简单,具体fatchSize设为多少要根据自己具体的业务需要和机器的配置来综合判定。

待解决问题
以上方式在xml中可以轻松设置,但是使用mybatis-plus的简单查询时并不用手动写xml查询,我也不知道如何定制其fatchSize的值,我目前的解决方式是手动在xml中再写一个查询方法来调用,但是感觉这样做非常的麻烦,如果你知道如何在调用mybatis-plus的BaseMapper查询方法时配置fatchSize,请留言告知,十分感谢!

如何优化hibernate性能

是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数,一般设置为30、50、100。Oracle数据库的JDBC驱动默认的Fetch
Size=15,设置Fetch
Size设置为:30、50,性能会有明显提升,如果继续增大,超出100,性能提升不明显,反而会消耗内存。
  即在hibernate配制文件中进行配制:
1 <property name="hibernateProperties">
2 <props>3 <propkey="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
4 <prop key="hibernate.show_sql">false</prop>
5 <!-- Create/update the database tables automatically when the JVMstarts up
6 <prop key="hibernate.hbm2ddl.auto">update</prop> -->
7 <!-- Turn batching off for better error messages underPostgreSQL
8 <prop key="hibernate.jdbc.batch_size">100</prop> -->
9 <prop key="hibernate.jdbc.batch_size">50</prop>
10 </props>
11 </property>Fetch Size设的越大,读数据库的次数越少,速度越快;Fetch
Size越小,读数据库的次数越多,速度越慢。
  2、如果是超大的系统,建议生成htm文件。加快页面提升速度。
  3、不要把所有的责任推在hibernate上,对代码进行重构,减少对数据库的操作,尽量避免在数据库查询时使用in操作,以及避免递归查询操作,代码质量、系统设计的合理性决定系统性能的高低。
  4、 对大数据量查询时,慎用list()或者iterator()返回查询结果,  (1).
使用List()返回结果时,Hibernate会所有查询结果初始化为持久化对象,结果集较大时,会占用很多的处理时间。  (2).
而使用iterator()返回结果时,在每次调用iterator.next()返回对象并使用对象时,Hibernate才调用查询将对应的对象初始化,对于大数据量时,每调用一次查询都会花费较多的时间。当结果集较大,但是含有较大量相同的数据,或者结果集不是全部都会使用时,使用iterator()才有优势。
  5、在一对多、多对一的关系中,使用延迟加载机制,会使不少的对象在使用时方会初始化,这样可使得节省内存空间以及减少数据库的负荷,而且若PO中的集合没有被使用时,就可减少互数据库的交互从而减少处理时间。
  6、对含有关联的PO(持久化对象)时,若default-cascade="all"或者
“save-update”,新增PO时,请注意对PO中的集合的赋值操作,因为有可能使得多执行一次update操作。
  7、对于大数据量新增、修改、删除操作或者是对大数据量的查询,与数据库的交互次数是决定处理时间的最重要因素,减少交互的次数是提升效率的最好途径,所以在开发过程中,请将show_sql设置为true,深入了解Hibernate的处理过程,尝试不同的方式,可以使得效率提升。尽可能对每个页面的显示,对数据库的操作减少到100----150条以内。越少越好。
  以上是在进行struts+hibernate+spring进行项目开发中,对hibernate性能优化的几点心得。

如何优化hibernate性能

是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数,一般设置为30、50、100。Oracle数据库的JDBC驱动默认的Fetch
Size=15,设置Fetch
Size设置为:30、50,性能会有明显提升,如果继续增大,超出100,性能提升不明显,反而会消耗内存。
  即在hibernate配制文件中进行配制:
1 <property name="hibernateProperties">
2 <props>3 <propkey="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
4 <prop key="hibernate.show_sql">false</prop>
5 <!-- Create/update the database tables automatically when the JVMstarts up
6 <prop key="hibernate.hbm2ddl.auto">update</prop> -->
7 <!-- Turn batching off for better error messages underPostgreSQL
8 <prop key="hibernate.jdbc.batch_size">100</prop> -->
9 <prop key="hibernate.jdbc.batch_size">50</prop>
10 </props>
11 </property>Fetch Size设的越大,读数据库的次数越少,速度越快;Fetch
Size越小,读数据库的次数越多,速度越慢。
  2、如果是超大的系统,建议生成htm文件。加快页面提升速度。
  3、不要把所有的责任推在hibernate上,对代码进行重构,减少对数据库的操作,尽量避免在数据库查询时使用in操作,以及避免递归查询操作,代码质量、系统设计的合理性决定系统性能的高低。
  4、 对大数据量查询时,慎用list()或者iterator()返回查询结果,  (1).
使用List()返回结果时,Hibernate会所有查询结果初始化为持久化对象,结果集较大时,会占用很多的处理时间。  (2).
而使用iterator()返回结果时,在每次调用iterator.next()返回对象并使用对象时,Hibernate才调用查询将对应的对象初始化,对于大数据量时,每调用一次查询都会花费较多的时间。当结果集较大,但是含有较大量相同的数据,或者结果集不是全部都会使用时,使用iterator()才有优势。
  5、在一对多、多对一的关系中,使用延迟加载机制,会使不少的对象在使用时方会初始化,这样可使得节省内存空间以及减少数据库的负荷,而且若PO中的集合没有被使用时,就可减少互数据库的交互从而减少处理时间。
  6、对含有关联的PO(持久化对象)时,若default-cascade="all"或者
“save-update”,新增PO时,请注意对PO中的集合的赋值操作,因为有可能使得多执行一次update操作。
  7、对于大数据量新增、修改、删除操作或者是对大数据量的查询,与数据库的交互次数是决定处理时间的最重要因素,减少交互的次数是提升效率的最好途径,所以在开发过程中,请将show_sql设置为true,深入了解Hibernate的处理过程,尝试不同的方式,可以使得效率提升。尽可能对每个页面的显示,对数据库的操作减少到100----150条以内。越少越好。
  以上是在进行struts+hibernate+spring进行项目开发中,对hibernate性能优化的几点心得。

jdbc查询db2的 setfetchsize能起作用吗

?????? 通过JDBC取数据时,默认是10条数据取一次,即fetch size为10,如果增大这个数字可以减少客户端与oracle的往返,减少响应时间,网上有建议这个数字不要超过100,要不然对中间件内存消耗大(没有做过实验)。 package com.gg.test;import java.sql.Conn

?????? 通过JDBC取数据时,默认是10条数据取一次,即fetch size为10,如果增大这个数字可以减少客户端与oracle的往返,减少响应时间,网上有建议这个数字不要超过100,要不然对中间件内存消耗大(没有做过实验)。

package com.gg.test;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;public class FetchSize { static final String driver_class = "oracle.jdbc.driver.OracleDriver"; static final String connectionURL = "jdbc:oracle:thin:@10.10.29.150:1522:ordb10"; static final String userID = "test"; static final String userPassword = "test"; public void runTest(int fetchSize) { Connection con = null; Statement stmt = null; ResultSet rset = null; long startTime =System.currentTimeMillis(); String query_string = "SELECT * FROM test";//test有5万条记录 try { Class.forName (driver_class).newInstance(); con = DriverManager.getConnection(connectionURL, userID, userPassword); stmt = con.createStatement(); stmt.setFetchSize(fetchSize); rset = stmt.executeQuery (query_string); while (rset.next ()) { rset.getString(1); rset.getString(2); rset.getString(3); } rset.close(); stmt.close(); long endTime =System.currentTimeMillis(); System.out.println("fetchsize为"+fetchSize+"---消耗的时间:"+(endTime-startTime)); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { FetchSize fetchSize = new FetchSize(); fetchSize.runTest(10); fetchSize.runTest(50); fetchSize.runTest(100); fetchSize.runTest(200); fetchSize.runTest(500); fetchSize.runTest(1000); }}


结果:

fetchsize为10?? ?---消耗的时间:22140ms
fetchsize为50??? ---消耗的时间:13780ms
fetchsize为100? ---消耗的时间:5110ms
fetchsize为200? ---消耗的时间:3984ms
fetchsize为500? ---消耗的时间:2625ms
fetchsize为1000---消耗的时间:2875ms

作者:guogang83 发表于2013-8-28 17:24:37 原文链接

阅读:7 评论:0 查看评论

原文地址:oracle jdbc fetchsize取值对性能的影响, 感谢原作者分享。

jdbc查询db2的 setfetchsize能起作用吗

?????? 通过JDBC取数据时,默认是10条数据取一次,即fetch size为10,如果增大这个数字可以减少客户端与oracle的往返,减少响应时间,网上有建议这个数字不要超过100,要不然对中间件内存消耗大(没有做过实验)。 package com.gg.test;import java.sql.Conn

?????? 通过JDBC取数据时,默认是10条数据取一次,即fetch size为10,如果增大这个数字可以减少客户端与oracle的往返,减少响应时间,网上有建议这个数字不要超过100,要不然对中间件内存消耗大(没有做过实验)。

package com.gg.test;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;public class FetchSize { static final String driver_class = "oracle.jdbc.driver.OracleDriver"; static final String connectionURL = "jdbc:oracle:thin:@10.10.29.150:1522:ordb10"; static final String userID = "test"; static final String userPassword = "test"; public void runTest(int fetchSize) { Connection con = null; Statement stmt = null; ResultSet rset = null; long startTime =System.currentTimeMillis(); String query_string = "SELECT * FROM test";//test有5万条记录 try { Class.forName (driver_class).newInstance(); con = DriverManager.getConnection(connectionURL, userID, userPassword); stmt = con.createStatement(); stmt.setFetchSize(fetchSize); rset = stmt.executeQuery (query_string); while (rset.next ()) { rset.getString(1); rset.getString(2); rset.getString(3); } rset.close(); stmt.close(); long endTime =System.currentTimeMillis(); System.out.println("fetchsize为"+fetchSize+"---消耗的时间:"+(endTime-startTime)); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { FetchSize fetchSize = new FetchSize(); fetchSize.runTest(10); fetchSize.runTest(50); fetchSize.runTest(100); fetchSize.runTest(200); fetchSize.runTest(500); fetchSize.runTest(1000); }}


结果:

fetchsize为10?? ?---消耗的时间:22140ms
fetchsize为50??? ---消耗的时间:13780ms
fetchsize为100? ---消耗的时间:5110ms
fetchsize为200? ---消耗的时间:3984ms
fetchsize为500? ---消耗的时间:2625ms
fetchsize为1000---消耗的时间:2875ms

作者:guogang83 发表于2013-8-28 17:24:37 原文链接

阅读:7 评论:0 查看评论

原文地址:oracle jdbc fetchsize取值对性能的影响, 感谢原作者分享。

使用jdbc从数据库查询数据,java程序需要考虑哪些优化方法

一、准备工作(一):MySQL安装配置和基础学习

使用JDBC操作数据库之前,首先你需要有一个数据库。这里提供了3个链接供读者自学,如果曾有过SQL语言的使用经历(包括在学校中的课堂学习),前两个链接足以上手。

1.安装和配置:mysql安装图解 mysql图文安装教程(详细说明)

2.基本操作:21分钟 MySQL 入门教程

3.简易命令查询 :一千行MySQL学习笔记

建议边看入门教程,边练习,在练习insert、update、select、delete等基本操作的同时,将后面要用的表建好。

下图是我接下来用于演示的数据库的表。

二、准备工作(二):下载数据库对应的jar包并导入

使用JDBC需要在工程中导入对应的jar包。数据库与JDBC包的对应关系可以参考各种数据库对应的jar包、驱动类名和URL格式。在Eclipse下的导入方法:

在工程的图标上右击,选择”Properties”,在”Java Bulid Path”中选择”Add External JARs…”,选择下载并解压后获得的jar包。

如果对MySQL进行操作,这时下面的import就不会报错了:

import com.mysql.jdbc.Connection;

import com.mysql.jdbc.PreparedStatement;

除此以外,还需要JDBC的包,直接import即可。

import java.sql.DriverManager;

import java.sql.ResultSet;

import java.sql.SQLException;

三、JDBC基本操作

为了简单起见,与数据库相关的操作、命令、参数都被硬编码了。有兴趣的读者可以对这些进行探索,降低数据与操作的耦合性。

先看具体代码并实践,本文第五部分对用到的API稍作了研究。

下面的所有方法和数据成员都在public class JDBCOperation内部。

(1)定义记录的类(可选)

这样做主要是为了便于操作和接口定义,是非必须的。

static class Student {

private String Id;

private String Name;

private String Sex;

private String Age;

Student(String Name, String Sex, String Age) {

this.Id = null; //default

this.Name = Name;

this.Sex = Sex;

this.Age = Age;

}

public String getId() {

return Id;

}

public void setId(String Id) {

this.Id = Id;

}

public String getName() {

return Name;

}

public void setName(String Name) {

this.Name = Name;

}

public String getSex() {

return Sex;

}

public void setSex(String Sex) {

this.Sex = Sex;

}

public String getAge() {

return Age;

}

public void setage(String Age) {

this.Age = Age;

}

}

(2)连接的获取

在操作前必须先获取与数据库的连接。

driver、url的格式同样可以参考各种数据库对应的jar包、驱动类名和URL格式。

private static Connection getConn() {

String driver = "com.mysql.jdbc.Driver";

String url = "jdbc:mysql://localhost:3306/samp_db";

String username = "root";

String password = "";

Connection conn = null;

try {

Class.forName(driver); //classLoader,加载对应驱动

conn = (Connection) DriverManager.getConnection(url, username, password);

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (SQLException e) {

e.printStackTrace();

}

return conn;

}

(3)insert

private static int insert(Student student) {

Connection conn = getConn();

int i = 0;

String sql = "insert into students (Name,Sex,Age) values(?,?,?)";

PreparedStatement pstmt;

try {

pstmt = (PreparedStatement) conn.prepareStatement(sql);

pstmt.setString(1, student.getName());

pstmt.setString(2, student.getSex());

pstmt.setString(3, student.getAge());

i = pstmt.executeUpdate();

pstmt.close();

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

return i;

}

(4)update

private static int update(Student student) {

Connection conn = getConn();

int i = 0;

String sql = "update students set Age='" + student.getAge() + "' where Name='" + student.getName() + "'";

PreparedStatement pstmt;

try {

pstmt = (PreparedStatement) conn.prepareStatement(sql);

i = pstmt.executeUpdate();

System.out.println("resutl: " + i);

pstmt.close();

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

return i;

}

(5)select

以select * from XXX为例。

private static Integer getAll() {

Connection conn = getConn();

String sql = "select * from students";

PreparedStatement pstmt;

try {

pstmt = (PreparedStatement)conn.prepareStatement(sql);

ResultSet rs = pstmt.executeQuery();

int col = rs.getMetaData().getColumnCount();

System.out.println("============================");

while (rs.next()) {

for (int i = 1; i <= col; i++) {

System.out.print(rs.getString(i) + "\t");

if ((i == 2) && (rs.getString(i).length() < 8)) {

System.out.print("\t");

}

}

System.out.println("");

}

System.out.println("============================");

} catch (SQLException e) {

e.printStackTrace();

}

return null;

}

(6)delete

private static int delete(String name) {

Connection conn = getConn();

int i = 0;

String sql = "delete from students where Name='" + name + "'";

PreparedStatement pstmt;

try {

pstmt = (PreparedStatement) conn.prepareStatement(sql);

i = pstmt.executeUpdate();

System.out.println("resutl: " + i);

pstmt.close();

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

return i;

}

jdbcfetch会取到相同的数据吗

1、通过查询,JDBC是将所有的查询结果一次性放到ResultSet中,还是一次只放一定数目的记录?例如,查询结果为2000条数据,JDBC是一次性将2000条数据放到结果集中,还是分批放置呢?

Answer:首先结果集resultset在你的java程序处。其中有个fetchsize设置,这个表示每次从数据库处取多少条记录到resultset,如果总查询数据量大于fetchsize.则进行分批放置,每次放置fetchsize条数据

2、当通过ResultSet.next(),移动结果集指针时,此时是否还与数据库发生交互?

Answer :此时分两种情况

第一种 交互

如果1个查询有10000条记录,resultset中只有fetchsize条,当next时还会在一定时机去交互

第二种 不发生交互

数据库执行完查询后,已经把所有查询结果交给ResultSet了,以后的操作,和数据库无关。

总结: exquertQuery()不是将查询结果一次性放到ResultSet中, 而是分批放入ResultSet中,一般情况下是每次10条记录,即fetchsize默认为10.

当数据到达第11条时,通过ResultSet.next(),移动结果集指针时,此时还会与数据库发生交互,但是在第1-10条数据时,通过ResultSet.next()移动结果集指针不与数据库发生交互.