是什么Statement.setFetchSize(n大小)方法确实在SQL Server JDBC

2019-06-18 18:35发布

我有每天数以百万计的一些记录,并在每一天,我提取前一天的所有记录结束这个真正的大桌。 我这样做,如:

String SQL =  "select col1, col2, coln from mytable where timecol = yesterday";
Statement.executeQuery(SQL);

问题是,这个程序需要像2GB的内存,因为它需要所有的结果在内存中,然后它处理它。

我尝试设置Statement.setFetchSize(10)但它恰恰是从OS不作任何区别相同的内存。 我使用的Microsoft SQL Server 2005 JDBC驱动程序这一点。

有没有办法读取像Oracle数据库驱动程序小块的结果时,不执行查询只显示几行和向下滚动查看更多结果显示?

Answer 1:

在JDBC中, setFetchSize(int)因为它控制的网络调用从JVM到数据库的数量和用于结果集处理的RAM相应的量的方法是在JVM中的性能和内存管理非常重要。

如果固有的setFetchSize(10)被调用,并且驱动程序忽略它,有可能只有两种选择:

  1. 尝试不同的JDBC驱动程序,将荣誉的获取大小的提示。
  2. 看看连接(URL和/或创建连接实例时财产地图)上驱动程序特定的属性。

结果集是响应查询编组的DB的行数。 该行集是被提取出每个呼叫的结果集从JVM到数据库的行块。 这些调用和处理所需所得RAM的数目是依赖于取尺寸设置。

因此,如果结果集有100行和取尺寸为10,将有10个网络调用来检索所有的数据,使用约10 * {行内容的大小} RAM在任何给定的时间。

默认提取大小是10,这是相当小的。 在这种情况下公布,它会出现在驱动程序忽略了取尺寸设置,在一个呼叫(大内存的要求,最佳最小的网络电话)获取的所有数据。

什么情况下ResultSet.next()是,它实际上并没有从结果集时获取一行。 它获取的是从(本地)ROW-SET和读取下一行-SET(不可见)的服务器,因为它成为本地客户机上用尽。

所有这一切都依赖于驱动程序的设置仅仅是一个“暗示”但在实践中,我发现这是如何工作的许多驱动程序和数据库(在Oracle,DB2和MySQL的许多版本验证)。



Answer 2:

fetchSize参数是一个暗示 ,JDBC驱动程序,以多行从数据库中要一次提取。 但司机是自由的忽略它,做它认为合适的。 一些司机,像甲骨文之一,在块读取行,这样你就可以在不需要大量内存读取的结果集非常大。 其他司机刚读整个结果一气呵成设定,我猜这就是你的驱动程序在做什么。

你可以试试你的驱动程序升级到SQL Server 2008的版本(这可能是更好),或开源JTDS驱动程序。



Answer 3:

您需要确保连接的自动提交被关闭 ,或将setFetchSize时没有任何效果。

dbConnection.setAutoCommit(false);

编辑:记得,当我用这个解决它的Postgres特有的,但希望它仍将为SQL Server工作。



Answer 4:

声明接口文件

发明内容: void setFetchSize(int rows)为JDBC驱动程序提供提示以应该从数据库中需要更多行时被提取的行的数量。

阅读这本电子书J2EE和超越艺术泰勒



Answer 5:

听起来像MSSQL JDBC是缓冲整个结果集为您服务。 您可以添加一个连接字符串参数说selectMode =光标或responseBuffering =适应性。 如果你是在2005年MSSQL JDBC驱动程序版本2.0或更高版本,然后响应缓冲应该默认为自适应。

http://msdn.microsoft.com/en-us/library/bb879937.aspx



Answer 6:

这听起来对我说,你真的要限制通过的结果返回的查询和页面行。 如果是这样,你可以这样做:

select * from (select rownum myrow, a.* from TEST1 a )
where myrow between 5 and 10 ;

你一定要确定你的边界。



Answer 7:

试试这个:

String SQL = "select col1, col2, coln from mytable where timecol = yesterday";

connection.setAutoCommit(false);
PreparedStatement stmt = connection.prepareStatement(SQL, SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY, SQLServerResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(2000);

stmt.set....

stmt.execute();
ResultSet rset = stmt.getResultSet();

while (rset.next()) {
    // ......


Answer 8:

我在一个项目有完全相同的问题。 问题是,即使获取大小可能是足够小,JdbcTemplate的读取查询的所有结果,并把它映射出这可能会打击你的记忆巨大的名单。 我结束了延长是NamedParameterJdbcTemplate创建返回对象的流的功能。 该流是基于通常由JDBC返回的ResultSet,但将仅作为流需要它的ResultSet中提取数据。 如果你不把所有该流吐对象的引用这将工作。 我没有激发自己对org.springframework.jdbc.core.JdbcTemplate#执行(org.springframework.jdbc.core.ConnectionCallback)实施了很多。 唯一真正的区别有什么用的ResultSet的事要做。 我结束了写这个功能的收官之ResultSet中:

private <T> Stream<T> wrapIntoStream(ResultSet rs, RowMapper<T> mapper) {
    CustomSpliterator<T> spliterator = new CustomSpliterator<T>(rs, mapper, Long.MAX_VALUE, NON-NULL | IMMUTABLE | ORDERED);
    Stream<T> stream = StreamSupport.stream(spliterator, false);
    return stream;
}
private static class CustomSpliterator<T> extends Spliterators.AbstractSpliterator<T> {
    // won't put code for constructor or properties here
    // the idea is to pull for the ResultSet and set into the Stream
    @Override
    public boolean tryAdvance(Consumer<? super T> action) {
        try {
            // you can add some logic to close the stream/Resultset automatically
            if(rs.next()) {
                T mapped = mapper.mapRow(rs, rowNumber++);
                action.accept(mapped);
                return true;
            } else {
                return false;
            }
        } catch (SQLException) {
            // do something with this Exception
        }
    }
}

你可以添加一些逻辑,以使该流“自动关闭的”,否则不要忘记关闭它,当你完成。



文章来源: What does Statement.setFetchSize(nSize) method really do in SQL Server JDBC driver?