Statement.setFetchSize(nSize)方法在SQL Server JDBC驱动程序中的作用是什么?

52 java sql-server jdbc

我有这个非常大的桌子,每天有数百万条记录,每天结束时我都会提取前一天的所有记录.我这样做:

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

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

我尝试设置Statement.setFetchSize(10)但它从操作系统获取完全相同的内存它没有任何区别.我正在使用Microsoft SQL Server 2005 JDBC驱动程序.

有没有办法以小块的形式读取结果,比如Oracle数据库驱动程序执行查询时只显示几行,当你向下滚动时会显示更多结果?

Dar*_*gue 65

在JDBC中,该setFetchSize(int)方法对于JVM中的性能和内存管理非常重要,因为它控制从JVM到数据库的网络调用的数量,以及相应的用于ResultSet处理的RAM量.

本质上,如果调用setFetchSize(10)并且驱动程序忽略它,则可能只有两个选项:

  1. 尝试使用不同的JDBC驱动程序来支持fetch-size提示.
  2. 查看Connection上的驱动程序特定属性(创建Connection实例时的URL和/或属性映射).

RESULT-SET是响应查询而在DB上编组的行数.ROW-SET是从JVM到DB的每次调用从RESULT-SET中取出的行块.处理所需的这些调用数和生成的RAM取决于fetch-size设置.

因此,如果RESULT-SET有100行且fetch-size为10,那么将有10个网络调用来检索所有数据,在任何给定时间使用大约10*{row-content-size} RAM.

默认的fetch-size是10,相当小.在发布的情况下,似乎驱动程序忽略了fetch-size设置,在一次调用中检索所有数据(大RAM要求,最佳最小网络调用).

下面发生的ResultSet.next()是它实际上并没有从RESULT-SET一次获取一行.它从(本地)ROW-SET中获取它,并在本地客户端上耗尽时从服务器获取下一个ROW-SET(不可见).

所有这一切都取决于驱动程序,因为设置只是一个"提示",但实际上我发现这是它如何适用于许多驱动程序和数据库(在许多版本的Oracle,DB2和MySQL中验证).

  • 滚动是向前/向后移动结果集的过程。要滚动,一个人固有地获取或可能已经获取到 JVM 内存中。尽管 JDBC 中的选项可以向后滚动获取的数据集,但各种数据库中的游标可能是仅向前的。所以 fetch-size 仍然是一种设置我们通过网络从数据库中提取多少数据的方式。滚动设置不会影响 JDBC 中的这一点。 (2认同)

ska*_*man 25

fetchSize参数是JDBC驱动程序的提示,指示要从数据库中一次获取的许多行.但是司机可以自由地忽略这一点并做它认为合适的事情.某些驱动程序(如Oracle的驱动程序)以块的形式获取行,因此您可以读取非常大的结果集而无需大量内存.其他驱动程序只需一次读取整个结果集,我猜你的驱动程序正在做什么.

您可以尝试将驱动程序升级到SQL Server 2008版本(可能更好)或开源jTDS驱动程序.

  • 完全正确.对于MSSQL,jTDS驱动程序是更好的选择. (2认同)

jwa*_*ell 14

您需要确保关闭 Connection上的自动提交,否则setFetchSize将不起作用.

dbConnection.setAutoCommit(false);
Run Code Online (Sandbox Code Playgroud)

编辑:记得当我使用此修复程序时它是Postgres特定的,但希望它仍然适用于SQL Server.

  • 我不知道Postgres但是...设置自动提交不应该对SELECT语句和/或查询fetch-size有任何引用(它们实际上是无关的). (6认同)

ada*_*ost 6

报表接口Doc

总结:void setFetchSize(int rows) 当需要更多行时,向 JDBC 驱动程序提供有关应从数据库中提取的行数的提示。

阅读这本电子书J2EE 及更高版本 作者:Art Taylor