3

In my application, I need to perform millions of queries to MySQL database. The codes look as follows:

for (int i=0; i< num_rows ; i++) {
   String query2="select id from mytable where x='"+ y.get(i) "'";              
   Statement stmt2 = Con0.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     
   ResultSet rs2 = stmt2.executeQuery(query2);    
   ... // process result in rs2
   rs2.close(); 
}

where num_rows is around 2 million. After 600k loops, java report an error and exit:

java.lang.OutOfMemoryError: Java heap space error.

What's wrong in my codes? How should I avoid such an error?

Thanks in advance!

2
  • 1
    what exactly are you doing here with the data? Commented Sep 8, 2011 at 15:55
  • SQL databases don't handle millions of queries terribly efficiently. This is because each query has a relatively high overhead. You are much better off batching your queries into blocks of say 100. google.com/search?q=jdbc+batching+performance Commented Sep 8, 2011 at 18:09

5 Answers 5

5

Close your statements as well.

Sign up to request clarification or add additional context in comments.

Comments

4

Statement is no good solution here. Try the following code:

PreparedStatement pre = Con0.prepareStatement("select id from mytable where x=?");

for (int i=0; i< num_rows ; i++) {
   pre.setString(1, y.get(i));
   ResultSet rs2 = pre.executeQuery();
   ... // process result in rs2
   rs2.close(); 
   pre.clearParameters();
}
pre.close();

Comments

2

I don't know if the answer accepted by you have solved your problem, since it doesn't change anything that could cause the problem.

The problem is when ResultSet is caching all the rows returned by the query, which can either be stored while you iterate through set, or prefetched. I've had similar problem with PostgreSQL JDBC driver, which ignored the cursor fetch size, when running in no-trasactional mode.

The JDBC driver should use cursors for such queries, so you should check driver's documentation about fetchSize parameter. As alternative, you can manage cursors yourself executing SQL command to create cursor and fetch next X rows.

Comments

1

Using a preparedStatement, since only the value of X changes in each loop, declared outside de loop should help. You're also, at least in the shown code, not closing the statement used, which might not help the garbage collector to free the used memory.

1 Comment

I take Johathan and Angelo's approach and it works very well. Thanks other guys, too.
1

Assuming that you are using a single connection for all your queries, and assuming your code is more complicated than what you show us, it is critical that you ensure that each Statement and each ResultSet is closed when you are finished with it. This means that you need a try/finally block like this:

for (int i=0; i< num_rows ; i++) {
  String query2="select id from mytable where x='"+ y.get(i) "'";              
  Statement stmt2 = Con0.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     
  ResultSet rs2 = null;   
  try {
    rs2 = stmt2.executeQuery(query2);    
    ... // process result in rs2
  } finally {
    try {
      stmt2.close();
    } catch (SQLException sqle) {
      // complain to logs
    }
    try {
      if (rs2 != null) { rs2.close(); }
    } catch (SQLException sqle) {
    }
  }
}

If you do not aggressively and deterministically close all result set and statement objects, and if you do requests quickly enough, you will run out of memory.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.