是否有一个尊重fetchSize的mysql JDBC?

时间:2014-09-25 19:08:04

标签: java mysql sql jdbc

我正在使用MySQL并希望使用setFetchSize属性。默认的MySQL JDBC实现并不真正尊重它。如果你将fetchsize设置为Integer.MIN_VALUE,它将分别获取每一行,但考虑到我想使用fetchSize的原因是我有足够的数据将我的内存使用量放到2 G范围内,每行必须进行一次查询要永远。

我想插入一个可以与MySQL一起使用的JDBC实现并正确地考虑提取大小,允许我设置10,000的提取量或其他一些更高的限制。任何人都可以指向一个可能提供这种实现的jar吗?失败的是,任何其他资源允许我合理地以有效的方式执行包含数万个条目的查询,但是在内存和所需的SQL查询数量中。

3 个答案:

答案 0 :(得分:15)

如果启用MySQL JDBC option useCursorFetch,驱动程序确实会尊重fetchSize。

但是,这种方法有一个缺点:它将使用服务器端游标,在MySQL中使用临时表实现。这意味着在服务器上完成查询之后结果才会到达,并且将在服务器端使用额外的内存。

如果您只想使用结果流而不关心确切的提取大小,setFetchSize(Integer.MIN_VALUE)的开销并不像文档所暗示的那样糟糕。它实际上只是禁用整个响应的客户端缓存,并在它们到达时为您提供响应;每行不需要往返。

答案 1 :(得分:4)

技术问题要求图书馆是偏离主题的。也就是说,据我所知,没有替代MySQL的驱动程序。您可以选择获取可能导致内存不足的所有行,也可以让驱动程序通过设置setFetchSize(Integer.MIN_VALUE)按需获取它们。

正如我从Connector/J implementation notes所理解的那样,原因是MySQL协议每个连接不能打开多个游标,因此它默认在执行时将所有行传输到客户端。

另一个选项是逐行检索行,但这会带来一个问题,即在处理ResultSet时无法在同一连接上执行其他语句:

  

这种方法有一些警告。您必须阅读结果集中所有行(或关闭它) 之前您可以在连接上发出任何其他查询,或者异常将被抛出。

所以MySQL只能选择获取所有内容或一次获取一个。这意味着驱动程序无法遵守不同的提取大小。由于在逐个获取时需要注意,他们选择使用Integer.MIN_VALUE(而不仅仅是1)作为您在此之前应该考虑的信号。

可能介于'之间'解决方案需要您使用LIMITOFFSET自行编程并重复执行查询。

答案 2 :(得分:1)

这不是上述问题的真正答案。由于我无法将其纳入评论,我将其作为答案提供。对于面临类似问题的人来说,这可能会有所帮助。

对于批处理作业,我需要打开流模式,因为我的结果集太大了。首先,如MySQL doc所示,我以这种方式建立连接:

Statement extrapackStreamingQuery = dbExtrapackConnection.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY); 
extrapackStreamingQuery.setFetchSize(Integer.MIN_VALUE);

但它会系统地给我错误:

Application was streaming results when the connection failed. Consider raising value of 'net_write_timeout' on the server.

我确实尝试了一些配置选项,例如:max_allowed_packet = 128Mmax_connect_errors = 9999net_write_timeout = 180。但他们都没有帮助。

错误地认为TCP连接可能因空闲时间过长而关闭,我甚至尝试使用net.ipv4.tcp_keepalive_time=60/proc/sys/net/ipv4/tcp_keepalive_time文件中的/etc/sysctl.conf更改TCP ping时间范围。< / p>

实际上,如果打开了数据库连接但没有发送足够长的TCP数据包,那么当TCP连接关闭时,数据库连接将丢失。更频繁地发送TCP数据包以保持TCP连接存活可以解决问题。

但这也没有帮助。

然后,在阅读此piece后,我将连接设置更改为:

protected static final int DB_STREAMING_FETCH_AMOUNT = 50;
...
Statement extrapackStreamingQuery = dbExtrapackConnection.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY);    
extrapackStreamingQuery.setFetchSize(DB_STREAMING_FETCH_AMOUNT);

使用我的网址使用尾随选项:

String fullUrl = url + host + ":" + port + "/" + dbName;
if (streaming) {
    fullUrl += "?useCursorFetch=true";
}

我的批处理工作现在工作正常,完成甚至更快运行。