在HSQLDB中选择100多万行

时间:2017-10-31 09:42:06

标签: java jdbc prepared-statement hsqldb

我必须在HSQLDB数据库中使用JDBC迭代一个包含超过100万条记录的表,而我无法在合理的时间内完成这项工作。我使用hsqldb v2.4.0。

我尝试使用带有以下查询的PreparedStatement对数据进行切片:

String select = "SELECT ID, NAME, VALUE FROM MY_TABLE ORDER BY ID OFFSET ? ROWS FETCH ? ROWS ONLY";

问题在于我们通过表格需要花费越来越多的时间。请注意,ID列已编入索引。

我尝试设置提取大小,但它也不起作用:

String select = "SELECT ID, NAME, VALUE FROM MY_TABLE";
PreparedStatement selectStatement = connection.prepareStatement(select, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
selectStatement.setFetchSize(5000);

然后我遍历ResultSet

ResultSet result = selectStatement.executeQuery();
while (result.next()) {
    Long id = result.getLong(1);
    // do stuff ...
} 

HSQLDB仍然尝试获取表的所有行,并且返回的ResultSet不适合内存。这是堆栈跟踪:

java.lang.OutOfMemoryError: Java heap space
at org.hsqldb.navigator.RowSetNavigatorData.ensureCapacity(Unknown Source)
at org.hsqldb.navigator.RowSetNavigatorData.add(Unknown Source)
at org.hsqldb.QuerySpecification.buildResult(Unknown Source)
at org.hsqldb.QuerySpecification.getSingleResult(Unknown Source)
at org.hsqldb.QuerySpecification.getResult(Unknown Source)
at org.hsqldb.StatementQuery.getResult(Unknown Source)
at org.hsqldb.StatementDMQL.execute(Unknown Source)
at org.hsqldb.Session.executeCompiledStatement(Unknown Source)
at org.hsqldb.Session.execute(Unknown Source)
at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(Unknown Source)
at org.hsqldb.jdbc.JDBCPreparedStatement.executeQuery(Unknown Source)
at com.jolbox.bonecp.PreparedStatementHandle.executeQuery(PreparedStatementHandle.java:174)
at myclass at the line ResultSet result = selectStatement.executeQuery();

有没有办法在HSQLDB中实现这个目标?

1 个答案:

答案 0 :(得分:3)

此问题与内存使用无关,因为此类SELECT不会使用太多内存。

预计选择结果的时间会增加。 SELECT中的OFFSET子句指示跳过多少行。随着它变大,选择并跳过更多行。

您需要将SELECT修改为:

SELECT ID, NAME, VALUE FROM MY_TABLE WHERE ID > ? ORDER BY ID FETCH ? ROWS ONLY

并使用带有PreparedStatement的正在运行的lastID来处理结果。

long lastID = -1;

// repeat the rest of the code until the result is empty
selectStatement.setLong(1, lastID);
selectStatement.setInt(2, 100000);

ResultSet result = selectStatement.executeQuery();
while (result.next()) {
 Long id = result.getLong(1);
 lastID = id;
 // do stuff ...
}

并且