Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read all rows from huge table?

I have a problem with processing all rows from database (PostgreSQL). I get an error: org.postgresql.util.PSQLException: Ran out of memory retrieving query results. I think that I need to read all rows in small pieces, but it doesn't work - it reads only 100 rows (code below). How to do that?

    int i = 0;           Statement s = connection.createStatement();     s.setMaxRows(100); // bacause of: org.postgresql.util.PSQLException: Ran out of memory retrieving query results.     ResultSet rs = s.executeQuery("select * from " + tabName);           for (;;) {         while (rs.next()) {             i++;             // do something...         }         if ((s.getMoreResults() == false) && (s.getUpdateCount() == -1)) {             break;         }                } 
like image 219
marioosh Avatar asked Sep 10 '10 06:09

marioosh


People also ask

How do you display all records of the table in a database?

The first command you will need to use is the SELECT FROM MySQL statement that has the following syntax: SELECT * FROM table_name; This is a basic MySQL query which will tell the script to select all the records from the table_name table.

How do I select data in chunks in SQL Server?

To retrieve large select by chunks, you need to use ORDER BY LIMIT. The syntax is as follows: SELECT *FROM yourTableName ORDER BY yourColumnName LIMIT 0,10; From the above syntax, you will get 10 rows from the table.


2 Answers

The short version is, call stmt.setFetchSize(50); and conn.setAutoCommit(false); to avoid reading the entire ResultSet into memory.

Here's what the docs say:

Getting results based on a cursor

By default the driver collects all the results for the query at once. This can be inconvenient for large data sets so the JDBC driver provides a means of basing a ResultSet on a database cursor and only fetching a small number of rows.

A small number of rows are cached on the client side of the connection and when exhausted the next block of rows is retrieved by repositioning the cursor.

Note:

  • Cursor based ResultSets cannot be used in all situations. There a number of restrictions which will make the driver silently fall back to fetching the whole ResultSet at once.

  • The connection to the server must be using the V3 protocol. This is the default for (and is only supported by) server versions 7.4 and later.-

  • The Connection must not be in autocommit mode. The backend closes cursors at the end of transactions, so in autocommit mode the backend will have closed the cursor before anything can be fetched from it.-

  • The Statement must be created with a ResultSet type of ResultSet.TYPE_FORWARD_ONLY. This is the default, so no code will need to be rewritten to take advantage of this, but it also means that you cannot scroll backwards or otherwise jump around in the ResultSet.-

  • The query given must be a single statement, not multiple statements strung together with semicolons.

Example 5.2. Setting fetch size to turn cursors on and off.

Changing code to cursor mode is as simple as setting the fetch size of the Statement to the appropriate size. Setting the fetch size back to 0 will cause all rows to be cached (the default behaviour).

// make sure autocommit is off conn.setAutoCommit(false); Statement st = conn.createStatement();  // Turn use of the cursor on. st.setFetchSize(50); ResultSet rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()) {    System.out.print("a row was returned."); } rs.close();  // Turn the cursor off. st.setFetchSize(0); rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()) {    System.out.print("many rows were returned."); } rs.close();  // Close the statement. st.close(); 

like image 153
nos Avatar answered Sep 18 '22 08:09

nos


Use a CURSOR in PostgreSQL or let the JDBC-driver handle this for you.

LIMIT and OFFSET will get slow when handling large datasets.

like image 25
Frank Heikens Avatar answered Sep 18 '22 08:09

Frank Heikens