Optimizing ResultSet fetch performance (Apache Spring, MySQL)

ControlAltDel picture ControlAltDel · May 8, 2012 · Viewed 7.3k times · Source

My problem is this: I am trying to process about 1.5 million rows of data in Spring via JDBCTemplate coming from MySQL. With such a large number of rows, I am using the RowCallbackHandler class as suggested here

The code is actually working, but's SLOW... The thing is that no matter what I set the fetch size to, I seem to get approximately 350 records per fetch, with a 2 to 3 second delay between fetches (from observing my logs). I tried commenting out the store command and confirmed that behavior stayed the same, so the problem is not with the writes.

There are 6 columns, only 1 that is a varchar, and that one is only 25 characters long, so I can't see throughput being the issue.

Ideally I'd like to get more like 30000-50000 rows at a time. Is there a way to do that?

Here is my code:


    protected void runCallback(String query, Map params, int fetchSize, RowCallbackHandler rch) 
            throws DatabaseException {
        int oldFetchSize = getJdbcTemplate().getFetchSize();
        if (fetchSize > 0) {
            getJdbcTemplate().setFetchSize(fetchSize);
        }
        try {
            getJdbcTemplate().query(getSql(query), rch);
        }
        catch (DataAccessException ex) {
            logger.error(ExceptionUtils.getStackTrace(ex));
            throw new DatabaseException( ex.getMessage() );         
        }
        getJdbcTemplate().setFetchSize(oldFetchSize);
    }

and the handler:

public class SaveUserFolderStatesCallback implements RowCallbackHandler {
        @Override
        public void processRow(ResultSet rs) throws SQLException {
            //Save each row sequentially.
            //Do NOT call ResultSet.next() !!!!

            Calendar asOf = Calendar.getInstance();
            log.info("AS OF DATE: " + asOf.getTime());
            Long x = (Long) rs.getLong("x");
            Long xx = (Long) rs.getLong("xx");
            String xxx = (String) rs.getString("xxx");
            BigDecimal xxxx = (BigDecimal)rs.getBigDecimal("xxxx");
            Double xxxx = (budgetAmountBD == null) ? 0.0 : budgetAmountBD.doubleValue();
            BigDecimal xxxxx = (BigDecimal)rs.getBigDecimal("xxxxx");
            Double xxxxx = (actualAmountBD == null) ? 0.0 : actualAmountBD.doubleValue();           

            dbstore(x, xx, xxx, xxxx, xxxxx, asOf);
        }       

    }

Answer

alexey28 picture alexey28 · May 8, 2012

And what is your query? Try to create an indexex for fields you are searching/sorting. That will help.

Second strategy: in memory cache implementation. Or using of hibernate plus 2nd level cache.

Both this technics can significantly speed up your query execution.