从大表读取时发生java.lang.OutOfMemoryError

从大表读取时发生java.lang.OutOfMemoryError,java,jdbc,out-of-memory,Java,Jdbc,Out Of Memory,我正在尝试从PostgreSQL中一个非常大的300GB表中预生成报告。我是这样做的: rs = stmt.executeQuery("SELECT * FROM tbl"); System.out.println("select all finished"); while (rs.next()) { /* generate report and save it in report table */ /* generated reports are not in memory,

我正在尝试从PostgreSQL中一个非常大的300GB表中预生成报告。我是这样做的:

rs = stmt.executeQuery("SELECT * FROM tbl");
System.out.println("select all finished");
while (rs.next()) {
    /* generate report and save it in report table */
    /* generated reports are not in memory, 
     * They are saved in a summary table in each iteration */
}
当我启动应用程序时,它在线程主java.lang.OutOfMemoryError:java堆空间中给出异常。我尝试使用stmt.setFetchSize1000,但它无法解决问题

解决办法是什么?我在Debian 6.0.5和openJDK 6上使用PostgreSQL 8.4.11

[更新]

打印的堆栈跟踪显示,已从tbl在rs=stmt.executeQuerySELECT*中生成OutOfMemoryError异常;线另外,System.out.PrintLn选择所有已完成;从不露面

我正在自动提交模式下运行。 stmt.getResultSetConcurrency返回1007。 stmt.getResultSetTholdability返回2。 rs.getType返回1003。
我不认为你那里的东西会导致那种错误。我相信垃圾收集器是在您迭代rs.next时出现的,所以您不应该有内存问题。它可能与您试图对结果集执行的操作有关。在不知道你在做什么的情况下,我只能猜测你试图将所有东西都存储在内存中的对象中。因此,如果要将值存储到StringBuilder或其他东西中,这将是一个问题。我建议在运行时将结果写入磁盘,而不是再次尝试将其收集到内存中的对象中,我只是猜测您在做什么,因为您没有提供此类信息。在中,有一种方法可能会对您有所帮助。以这种方式处理它可以防止您将其全部保存在内存中,但您可以编写您尝试编写的报告。顺便说一下,要做到这一点,您需要包括。或者,您可以直接调用该方法,方法包括


问题可能是PostgreSQL只在一小部分情况下使用fetchSize。见:

与服务器的连接必须使用V3协议。这是的默认设置,仅受服务器版本7.4及更高版本的支持。 连接不能处于自动提交模式。后端在事务结束时关闭游标,因此在自动提交模式下,后端将在从游标中提取任何内容之前关闭游标。 必须使用ResultSet.type\u FORWARD\u的ResultSet类型创建语句。这是默认设置,因此不需要重写代码来利用这一点,但这也意味着您不能在结果集中向后滚动或以其他方式跳转。 给定的查询必须是单个语句,而不是用分号串在一起的多个语句。
因此,如果您在自动提交中执行此操作,或者使用除类型_FORWARD _之外的resultset类型,则只有PostgreSQL将获取所有行。另外,看看PostgreSQL JDBC 9.0-801驱动程序的源代码,使用可保留的resultset看起来也会使它获取所有行。

您真的需要所有列吗…?解决方案是使用更少的内存resultset类型和可保留性是什么?您是使用自动提交还是不使用自动提交执行?
 /**
   * Prints the given ResultSet to a comma separated file (the destination)
   *
   * @param rs
   * @param destination
   * @throws SQLException
   * @throws FileNotFoundException
   */
  public static void resultSetToCSVFile(ResultSet rs, String destination) throws SQLException, FileNotFoundException, IOException {
    ResultSetMetaData metaData = rs.getMetaData();
    int columnCount = metaData.getColumnCount();
    String[] header = new String[columnCount];
    for (int i = 0; i < columnCount; i++) {
      header[i] = metaData.getColumnName(i + 1);
    }
    File file = new File(destination);
    IOHelper.checkDirectory(file);
    try (PrintWriter pw = new PrintWriter(file); CSVWriter writer = new CSVWriter(pw)) {
      writer.writeNext(header);
      while (rs.next()) {
        String[] row = new String[columnCount];
        for (int i = 0; i < columnCount; i++) {
          String string = rs.getString(i + 1);
          if (string == null) {
            string = "";
          }
          row[i] = string;
        }
        writer.writeNext(row);
      }
    }
  }