【问题标题】:Really streaming large MySQL result sets真正流式传输大型 MySQL 结果集
【发布时间】:2016-06-23 01:05:27
【问题描述】:

有一个similar question about streaming large results,但答案只是指向文档,没有明确的答案出现。 我相信仅treating a full result set as a stream 在 jdbc 驱动端仍然会占用大量内存..

我想知道是否有任何明确的模式或最佳实践可以让它发挥作用,尤其是在 jdbc 驱动程序方面。

特别是我不知道为什么setFetchSize(Integer.MIN_VALUE) 是一个非常好的主意,因为如果这意味着每行都通过网络单独发送,这似乎远非最佳。

我相信像 jooq 和 slick 这样的库已经解决了这个问题......并且很好奇如何在有和没有它们的情况下完成它。

谢谢!

【问题讨论】:

  • P.S.在使用 slick 时,postgres 有一些涉及和特定的东西:stackoverflow.com/questions/31340507/…
  • 文档 (dev.mysql.com/doc/connector-j/en/…) 说要么所有内容都加载到内存中,要么逐一检索行。其他数据库驱动程序有更明智的方法。
  • 不,我不是。但是,如果有其他选择,那就应该讨论它。这里还记录了 useCursorFetch 属性 (dev.mysql.com/doc/connector-j/en/…),但我不清楚它的确切含义,以及 fetchSize 的实际值是否用于任何用途。
  • 最近的相关问题here 可能很有趣,特别是关于使用 MySQL 的 JDBC 方面。
  • 为了记录(因为您用jooq 标记了这个问题),jOOQ 在这里没有也不应该帮助您。流式传输服务器网络协议的职责。 JDBC 是协议抽象 API。 jOOQ 是一种 SQL 语言抽象 API,因此不应干扰 JDBC。虽然 jOOQ 确实支持 java.util.stream.Stream 用于流式传输结果,但这种高级抽象并未假设记录是如何通过网络传输的。

标签: mysql scala jdbc jooq


【解决方案1】:

我想知道是否有任何明确的模式或最佳实践可以让它工作,尤其是在 jdbc 驱动程序方面。

最佳做法是不进行同步流式传输,而是获取中等大小的块。但是避免使用OFFSET(也可以是see)。如果您进行批处理,可以通过首先选择数据并将其推送到临时表中来促进这一点(即,首先将您想要的原始结果转换为表,然后从表中选择块......数据库在复制数据方面非常快内部)。

同步流通常无法扩展(也称为迭代器)。它不能很好地用于批处理,当然也不能用于处理大量客户端。这就是为什么驱动程序会发生变化并做很多不同的事情的原因,因为它是一个拉模型,因此很难弄清楚要加载多少资源。异步流(推送模型)可能会有所帮助,但不幸的是 JDBC 标准不支持异步流。

您可能会注意到,但这就是为什么围绕 JDBC 的许多包装器(例如 Spring JDBC)不返回 Iterators 的原因之一(此外还需要手动清理资源)。一些包装器提供了迭代器,但实际上它们只是将结果转换为列表。

您与 Scala 版本的链接相当令人不安,鉴于管理 ResultSet 的有状态性质,它被赞成...它非常不像 Scala...我不确定那些人是否知道他们必须使用迭代器或正确关闭连接/结果集,这需要大量的命令式编程。

虽然让数据库决定缓冲多少似乎效率低下,但请记住,大多数数据库连接在内存方面都非常繁重(至少在 postgres 上是这样)。因此,如果您需要很长时间进行流式传输并且拥有许多客户端,您将不得不创建更多连接并给数据库带来严重负担。更不用说默认缓冲区可能已经过高度优化(即客户端最终得到的结果集大小)。

最后,批处理块可以并行完成,这显然比同步管道更有效,并且在出现问题时重新启动(无需重新处理已处理的数据)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 2017-09-20
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 2017-07-02
    相关资源
    最近更新 更多