有一个similar question about streaming large results,但答案仅指向文档,并且没有明确的答案。 我相信只有treating a full result set as a stream仍然需要jdbc驱动程序端的大量内存..
我想知道是否有任何明确的切割模式或最佳实践,以使其工作,尤其是在jdbc驱动程序方面。
特别是我不确定为什么setFetchSize(Integer.MIN_VALUE)
是一个非常好的主意,因为它似乎远非最佳,如果这意味着每一行都是在线上自己发送的。
我相信像jooq和slick这样的图书馆已经照顾到了这一点......我很好奇如何使用和不使用它们来实现它。
谢谢!
答案 0 :(得分:1)
我想知道是否有任何明确的剪切模式或最佳实践,以使其工作,尤其是在jdbc驱动程序方面。
最佳做法是不要进行同步流,而是采用中等大小的块进行抓取。但请避免使用OFFSET
(也see)。如果您正在进行批处理,可以通过首先选择并将数据推送到临时表中来促进这一点(即,首先将您想要的原始结果转换为表格,然后从表格中选择块...数据库在复制数据方面非常快内部)。
同步流通常不会扩展(也就是迭代器)。它对于批处理来说不能很好地扩展,并且它当然不能扩展以处理客户端的负载。这就是为什么驱动程序变化并做了很多不同的事情,因为它很难确定要加载多少资源,因为它是拉模型。异步流(推送模型)可能有所帮助,但不幸的是,JDBC标准不支持异步流。
您可能会注意到,但这是围绕JDBC的许多包装器(如Spring JDBC)不返回Iterator
的原因之一(以及需要手动清理资源的事实)。一些包装器提供了迭代器,但实际上它们只是将结果转换为列表。
你对Scala版本的链接相当令人不安,因为它管理了一个ResultSet的状态本质...它非常非scala ...我不确定那些人知道他们必须使用迭代器或者正确关闭连接/ ResultSet,这需要大量的命令式编程。
虽然让数据库决定缓冲多少只是记住大多数数据库连接都是非常重的内存(至少在postgres上),这似乎效率低下。因此,如果您花费很长时间进行流式处理并拥有许多客户端,则必须创建更多连接并对数据库造成严重负担。更不用说默认缓冲区可能已经过高度优化(即客户端最终得到的结果集大小)。
最后,对于批处理,可以并行完成块,这显然比同步管道更有效,并且如果出现问题则重新启动(不必重新处理已处理的数据)。