Java JOOQ从大表中获取数据:良好实践

Java JOOQ从大表中获取数据:良好实践,java,postgresql,garbage-collection,out-of-memory,jooq,Java,Postgresql,Garbage Collection,Out Of Memory,Jooq,我有一个外部api,一个用来下载,另一个用来从db表[postgresql]上传数据。这张桌子相当大。随着时间的推移,我们观察到服务器缓慢地继续占用内存,但并没有太多地删除内存,它抛出错误并退出(有时linux会关闭它)。我检查了内存转储,无法找出与代码相关的任何内容。我不使用任何本地缓存或类似的东西。但是今天我得到了这个- java.lang.OutOfMemoryError: GC overhead limit exceeded at java.sql.Timestamp.t

我有一个外部api,一个用来下载,另一个用来从db表[postgresql]上传数据。这张桌子相当大。随着时间的推移,我们观察到服务器缓慢地继续占用内存,但并没有太多地删除内存,它抛出错误并退出(有时linux会关闭它)。我检查了内存转储,无法找出与代码相关的任何内容。我不使用任何本地缓存或类似的东西。但是今天我得到了这个-

java.lang.OutOfMemoryError: GC overhead limit exceeded
        at java.sql.Timestamp.toString(Timestamp.java:350)
        at java.lang.String.valueOf(String.java:2994)
        at org.jooq.impl.AbstractParam.name(AbstractParam.java:107)
        at org.jooq.impl.AbstractParam.<init>(AbstractParam.java:81)
        at org.jooq.impl.AbstractParam.<init>(AbstractParam.java:77)
        at org.jooq.impl.Val.<init>(Val.java:63)
        at org.jooq.impl.DSL.val(DSL.java:15157)
        at org.jooq.impl.Tools.field(Tools.java:1092)
        at org.jooq.impl.Tools.fields(Tools.java:1226)
        at org.jooq.impl.BatchSingle.executePrepared(BatchSingle.java:231)
        at org.jooq.impl.BatchSingle.execute(BatchSingle.java:182)
        at org.jooq.impl.BatchCRUD.executePrepared(BatchCRUD.java:159)
        at org.jooq.impl.BatchCRUD.execute(BatchCRUD.java:100)
java.lang.OutOfMemoryError:超出GC开销限制
位于java.sql.Timestamp.toString(Timestamp.java:350)
位于java.lang.String.valueOf(String.java:2994)
位于org.jooq.impl.AbstractParam.name(AbstractParam.java:107)
位于org.jooq.impl.AbstractParam(AbstractParam.java:81)
位于org.jooq.impl.AbstractParam(AbstractParam.java:77)
位于org.jooq.impl.Val(Val.java:63)
位于org.jooq.impl.DSL.val(DSL.java:15157)
位于org.jooq.impl.Tools.field(Tools.java:1092)
位于org.jooq.impl.Tools.fields(Tools.java:1226)
位于org.jooq.impl.BatchSingle.executePrepared(BatchSingle.java:231)
位于org.jooq.impl.BatchSingle.execute(BatchSingle.java:182)
位于org.jooq.impl.BatchCRUD.executePrepared(BatchCRUD.java:159)
位于org.jooq.impl.BatchCRUD.execute(BatchCRUD.java:100)
对于获取,我使用普通的
fetch
函数,对于将数据转储到数据库,我使用JOOQ的
batchInsert
batchUpdate
方法。JOOQ是否有处理大型数据集的良好实践?我遗漏了什么吗?

这两个
fetch()
batchInsert()
/
batchUpdate()
都将缓冲您的内容,即您的结果和/或绑定变量。在使用jOOQ时,不建议使用这种方法。让我们分别来看这两种操作:

大量阅读 对于大型读取,应避免
fetch()
,因为这将从数据库中获取所有记录,并在使用它们之前将它们存储在内存中。在大多数情况下,这是比保持打开游标/资源(JDBC的方式)更好的方法,但是在结果很大的情况下,这是禁止的。相反,您应该使用或:

//使用fetchLazy():
try(Cursor Cursor=query.fetchLazy()){
...
}
//使用fetchStream():
try(Stream=query.fetchStream()){
...
}
不要忘记使用try with resources,以确保在完成时关闭所有资源,例如
ResultSet
PreparedStatement

请注意还有一个,它允许防止PostgreSQL JDBC驱动程序缓冲过多的行

大字 您不应该在任何数据库中一次性编写大量插入。除了可能遇到的客户端内存问题外,还存在与不断增长的撤消/重做日志相关的服务器端问题的风险。理想情况下,您应该通过微调将写操作划分为小块:

  • 体积大小
  • 批量
  • 提交大小
jOOQ知道导入CSV/JSON/数组数据的
Loader
API,并负责上述微调。这里有记录:

// Using fetchLazy():
try (Cursor<Record> cursor = query.fetchLazy()) {
    ...
}

// Using fetchStream():
try (Stream<Record> stream = query.fetchStream()) {
    ...
}