尝试从mysql表检索一百万行时,如何避免Java中的内存不足堆空间错误?

时间:2018-08-02 17:00:09

标签: java mysql jdbc

我在atRsSelect = oPrStmt.executeQuery();中遇到了内存不足的堆空间错误。 该函数从名为“ snomedinfo_data”的mysql表中检索一百万条记录:

public String getSnomedCodes()
{
    Root oRoot = null;
    JSONObject oJsonSno = null;
    JSONObject oJson = null;
    JSONArray oJsonArr = null;
    ResultSet oRsSelect = null;
    PreparedStatement oPrStmt = null;
    String strSql = null;
    String snomedcode=null;
    String snomeddesc=null;
    String str=null;
    int cStart = 0;

    try {
        oJsonSno = new JSONObject();
        oJson = new JSONObject();
        oJsonArr = new JSONArray();
        oRoot = Root.createDbConnection(null);
//retrieving data from table        
        strSql = "SELECT * FROM snomedinfo_data   ;";

        oPrStmt = oRoot.con.prepareStatement(strSql);


        oRsSelect = oPrStmt.executeQuery();
        while (oRsSelect.next()) {
            snomedcode = Root.TrimString(oRsSelect.getString("conceptid"));
            snomeddesc = Root.TrimString(oRsSelect.getString("term"));
            oJsonSno = new JSONObject();
            oJsonSno.put("snomedcode",snomedcode);
            oJsonSno.put("snomeddesc",snomeddesc);
            oJsonArr.put(oJsonSno);
        }
        oJson.put("status", "success");
        oJson.put("snomeddata", oJsonArr);
        str = oJson.toString(); 
    }
    catch (Exception e) {
        e.printStackTrace();

    }

    finally {

        oRsSelect = Root.EcwCloseResultSet(oRsSelect);

        oPrStmt = Root.EcwClosePreparedStatement(oPrStmt);
        oRoot = Root.closeDbConnection(null, oRoot);
    }

    return str; 
}




I get a out of memory heap space error at- oRsSelect = oPrStmt.executeQuery();

I have tried using -


 strSql = "SELECT * FROM snomedinfo_data   ;";
            oRoot.con.setAutoCommit(false);
            oPrStmt = oRoot.con.prepareStatement(strSql);
            oPrStmt = oRoot.con.prepareStatement(strSql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
        oPrStmt.setFetchSize(Integer.MIN_VALUE);
            oRsSelect = oPrStmt.executeQuery();

但是它仍然无法正常工作,并继续出现内存不足的堆空间错误。请帮忙!

2 个答案:

答案 0 :(得分:1)

据我所知,MySQL不支持结果集缓冲。

这意味着MySQL立即向您发送所有行。理论上定义fetchSize是为了处理这些情况,但这只是对JDBC驱动程序和RDBMS的建议。

根据Gord Thompson的related answer,显然,如果配置正确,MySQL显然可以遵守fecthSize。这需要在JDBC连接URL中设置参数useCursorFetch=true。您需要测试您的MySQL版本和JDBC驱动程序版本是否遵守。

其他解决方案?嗯...我还没有测试过这些,但是至少我可以描述它们,所以您可以看看它们是否值得努力:

  1. 使用光标。检索游标而不是简单的SQL select。然后,您可以检索和处理较小块的行。

  2. 使用分页。有些查询自然支持分页。它们需要按一组唯一的列进行排序。这样,您可以多次执行查询,因此一次只能获得10000行。不利的一面:如果不断修改数据,可能会导致结果集不一致。原始的单个SELECT查询完全是 transactional ,而此解决方案不是。如果这是在不修改表的情况下进行的每晚处理,则此不利方面可能不相关。

两种解决方案的最大缺点是它们需要更多的工作。更多的应用程序工作量,更多的SQL工作量,更多的调试工作量。如果太多,也许您应该考虑升级到PostgreSQL,DB2或Oracle,它们确实实现了缓冲。

或者,MariaDB可能支持它(并且与MySQL非常相似),但是我不会打赌。

答案 1 :(得分:0)

您可以通过将参数传递给JVM来简单地增加内存堆大小:

-Xmx2G

“ 2G”代表2GB的内存。您可以对GB使用“ G”,对于MB使用“ M”,对于KB使用“ K”。试试看,并使用您需要的数量和可用的数量。您可以在其中here

进行一些阅读

如果它仍在使用大量内存,那么您可以考虑考虑为MySQL查询启用流式结果,因此ResultSet不会一次全部加载到内存中-当然,这是以性能为代价的:

oPrStmt = oRoot.con.prepareStatement(strSql);
oPrStmt.setFetchSize(Integer.MIN_VALUE); // Code to use minimum fetching size
oRsSelect = oPrStmt.executeQuery();