Reputation: 887
I am executing select query on a table of MYSQL which has 16,213,156 rows and 10 columns. But after connection is established code just executes for few mins and then throws error : Exception in thread "Thread-3" java.lang.OutOfMemoryError: Java heap space
My system configuration is 16 gb RAM, Java 8
I tried setting Jvm Parameters as -Xms4G & -Xmx12G . Also tried setting stmt.setFetchSize(); // to 10,100,1000 still same error
Can we fetch such large number of records using JDBC API am I missing anything ? Any help would be really appreciated.
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();
}
}
}
Upvotes: 7
Views: 20961
Reputation: 887
@MickMnemonic Thanks for your help this solved the issue.
Setting fetchSize alone might not be enough for the MySQL driver to start streaming the data from the DB instead of loading everything at once. You could try with
stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY); stmt.setFetchSize(Integer.MIN_VALUE);
Upvotes: 7
Reputation: 149
Limit the query, like,
SELECT * FROM message_history limit {start from row no.} , {no. of rows to select}
example-
SELECT * FROM message_history limit 100000,200000;
will retrieve rows from 100000 to 300000; like this divide into batches.also
PreparedStatement statement = con.prepareStatement(query);
statement.setFetchSize(Integer.MIN_VALUE);
rs = statement.executeQuery();
This method worked for me to retrieve 22 million records.
Upvotes: 0
Reputation: 458
I've run into a similar problem reading some million rows from a MySQL DB. I'm reading with a PreparedStatement called reader. Then just after the PrepareStatement I've reduced the fetchsize to minimum:
PreparedStatement reader = connection.prepareStatement("select....");
reader.setFetchSize(Integer.MIN_VALUE);
and from then on, I've never run into problems.
Upvotes: -1
Reputation: 2561
If you want to some searching or manipulation try to do at database Layer rather to fetch all of them in Application Layer and then do manipulation/searching. Getting the large set of records is not good practice. Provide the search filter option there so that user can filter the records as per their need, as records grow this really tedious task for you to manage all these.
Upvotes: -1