【问题标题】:Java how to retrieve more than 1 million rows in a ResultsetJava如何在Resultset中检索超过100万行
【发布时间】:2018-11-29 21:21:18
【问题描述】:

我正在对具有 16,213,156 行和 10 列的 MYSQL 表执行选择查询。但是在建立连接后,代码只执行了几分钟然后抛出错误:Exception in thread "Thread-3" java.lang.OutOfMemoryError: Java heap space

我的系统配置是 16 GB RAM,Java 8

我尝试将 Jvm 参数设置为 -Xms4G 和 -Xmx12G 。还尝试设置 stmt.setFetchSize(); // 到 10,100,1000 还是一样的错误

我们可以使用 JDBC API 获取如此大量的记录吗?我错过了什么吗?任何帮助将不胜感激。

package com;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;

import com.opencsv.CSVWriter;

public class Test1 {
    private static Connection conn = null;

    public static void main(String[] args) throws ClassNotFoundException, SQLException, IOException {

        connection();
        retrieve(conn);

    }



    public static void connection()
    {

        try
        {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "<jdbc connection url>";
            conn = DriverManager.getConnection(url, "<username>", "<password>");
            System.out.println("Connection established");       
        }

        catch(Exception e)
        {
            e.printStackTrace();
        }

    }


    public static void retrieve(Connection conn)
    {
        ResultSet rs = null;
        Statement stmt = null;
        try
        {

            stmt = conn.createStatement();
            //  stmt.setFetchSize(100); // 1000, 10
            System.out.println(stmt.getFetchSize());  // By default prints 0
            rs = stmt.executeQuery("SELECT * FROM tablename");
            CSVWriter writer = new CSVWriter(new BufferedWriter(new FileWriter("C:\\finaldata\\test.csv")));
            System.out.println("**** Started writing Data to CSV ****");
            int lines = writer.writeAll(rs, true, false, false);        
            writer.flush();
            writer.close();
            System.out.println("** OpenCSV -Completed writing the resultSet at " +  new Date() + " Number of lines written to the file " + lines);  

        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}

【问题讨论】:

  • 为什么要在结果集中检索超过 100 万行?
  • 为什么不分页?抓取记录 0-20、21-40、41-60 等...
  • 你用分析器检查过什么消耗内存吗?使用 ResultSet 可以逐条提取数亿条记录
  • 我同意@Ivan,您将不得不对此进行记忆分析。代码没有明显的问题。在内部,writeAll() 应用于 ResultSet 一次迭代一行。
  • 单独设置获取大小可能不足以让 MySQL 驱动程序开始从数据库流式传输数据,而不是一次加载所有内容。你可以试试stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); stmt.setFetchSize(Integer.MIN_VALUE);(来自this answer)。

标签: java jdbc


【解决方案1】:

@MickMnemonic 感谢您的帮助,这解决了问题。

单独设置 fetchSize 可能不足以让 MySQL 驱动程序开始从数据库流式传输数据,而不是一次加载所有内容。你可以试试

stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, 
ResultSet.CONCUR_READ_ONLY); stmt.setFetchSize(Integer.MIN_VALUE);

【讨论】:

    【解决方案2】:

    限制查询,比如,

    SELECT * FROM message_history limit {start from row no.} , {no. of rows to select}
    

    例子-

    SELECT * FROM message_history limit 100000,200000;
    

    将检索从 100000 到 300000 的行; 像这样分批。也

    PreparedStatement statement = con.prepareStatement(query);
    statement.setFetchSize(Integer.MIN_VALUE);
    rs = statement.executeQuery();
    

    这个方法帮我检索了 2200 万条记录。

    【讨论】:

      【解决方案3】:

      我在从 MySQL 数据库中读取数百万行时遇到了类似的问题。 我正在使用名为 reader 的 PreparedStatement 阅读。然后就在 PrepareStatement 之后,我将 fetchsize 减少到最小:

      PreparedStatement reader = connection.prepareStatement("select....");
      reader.setFetchSize(Integer.MIN_VALUE);
      

      从那时起,我再也没有遇到过问题。

      【讨论】:

      【解决方案4】:

      如果您想进行一些搜索或操作,请尝试在数据库层进行,而不是在应用程序层获取所有这些,然后进行操作/搜索。获取大量记录并不是一个好习惯。在那里提供搜索过滤器选项,以便用户可以根据需要过滤记录,随着记录的增长,这项非常繁琐的任务需要您来管理。

      【讨论】:

      • 这并不能真正回答问题,更多的是评论。此外,在writeAll() 应用于ResultSet 的幕后,一次遍历结果集一行并且不会将所有记录加载到内存中。其他事情正在发生。
      • 一次设置一行是什么意思,sql查询呢。由于调用是同步的,因此数据库服务器立即返回所有记录。你会怎么说那些不会加载到内存中。你能证明吗?
      猜你喜欢
      • 2016-01-24
      • 1970-01-01
      • 2013-04-13
      • 1970-01-01
      • 2023-02-19
      • 2021-11-27
      • 1970-01-01
      • 1970-01-01
      • 2018-11-06
      相关资源
      最近更新 更多