我在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();
但是它仍然无法正常工作,并继续出现内存不足的堆空间错误。请帮忙!
答案 0 :(得分:1)
据我所知,MySQL不支持结果集缓冲。
这意味着MySQL立即向您发送所有行。理论上定义fetchSize
是为了处理这些情况,但这只是对JDBC驱动程序和RDBMS的建议。
根据Gord Thompson的related answer,显然,如果配置正确,MySQL显然可以遵守fecthSize
。这需要在JDBC连接URL中设置参数useCursorFetch=true
。您需要测试您的MySQL版本和JDBC驱动程序版本是否遵守。
其他解决方案?嗯...我还没有测试过这些,但是至少我可以描述它们,所以您可以看看它们是否值得努力:
使用光标。检索游标而不是简单的SQL select
。然后,您可以检索和处理较小块的行。
使用分页。有些查询自然支持分页。它们需要按一组唯一的列进行排序。这样,您可以多次执行查询,因此一次只能获得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();