0

我有一个应用程序迭代大量的结果集并从不同的表中查询每一行的附加信息。

大致的结构是这样的:

public void main(String[] args) {
    ResultSet result = database.connection.createStatement()
                           .executeQuery("SELECT * FROM entities");
    ArrayList<Entity> entities = new ArrayList<Entity>();
    while (result.next() {
        Entity entity = EntityFactory.createById(result.getInt("id"));
        entities.add(entity);
    }
}

// EntityFactory
public static Entity createById(int id) {
    StringBuilder sql = new StringBuilder("SELECT * FROM sampling_data WHERE id = ")
                            .append(id);
    ResultSet result = database.connection.createStatement()
                            .executeQuery(sql.toString());
    result.first();
    EntityData data = new EntityData(25);

    for (int sample = 1; sample <= 25; sample++) {
        String sample_R = new StringBuilder("sample_")
                              .append(sample).append("_R").toString();
        String sample_G = new StringBuilder("sample_")
                              .append(sample).append("_G").toString();
        String sample_B = new StringBuilder("sample_")
                              .append(sample).append("_B").toString();

        int r = resultSet.getInt(sample_R);
        int g = resultSet.getInt(sample_G);
        int b = resultSet.getInt(sample_B);

        data.add(r, g, b);
    }

    return new Entity(data);
}

这会导致 OutOfMemoryException。

如何使循环(或整个方法)的内存效率更高?

4

3 回答 3

0

从代码的一瞥中很难分辨,但我认为这与完全获取的行数过多有关。

你应该使用setFetchSize(int rows)在你Statement的行数合理(可能是 100 行)。

    private static int FETCH_SIZE = 100;
    ...
    Statement stmt = databaseConnection.createStatement()
    stmt.setFetchSize();
    ResultSet result = stmt.executeQuery("SELECT * FROM sampling_data");
于 2012-04-22T12:32:10.210 回答
0

似乎 getInt() 方法在循环中执行时会使用大量内存。

这是不正确的。没有什么特别getInt()的原因导致你的问题。

您的架构打破了关系数据库的第一个正常形式。看到sample_1_R, sample_1_G, sample_1_B也让我质疑你的其他决定。这显然是一种1:m关系。像 25 这样的幻数也是如此。

我想知道您为什么要使用 String builder 和 int 来做所有这些事情。我会将这些 RGB 值封装到一个有意义的对象中,例如java.awt.Color.

我们在这里谈论多少数据?

25*3*32*2500 ~ 5.7 MB

这对于您的 2500 行来说并不多,每行都有 75 个整数值。从您的代码中不清楚的其他事情正在发生。

更新:

(n+1)在此代码中犯了典型的查询错误。您获得所有实体,然后遍历它们以获取 RGB 值。我建议做一个 JOIN 并立即将它们全部带回来。这可能无法解释您的内存问题,但这是一个问题。

当您查询 RGB 值时,您会重复建立列名。这完全是浪费。使它们static final String成为数组中的实例。

于 2012-04-22T12:33:36.330 回答
0

最大的问题是(我认为)createById 没有关闭结果集和语句。此外,没有 nx1 查询是有意义的。

    try {
        Statement stmt = database.connection.createStatement();
        ResultSet result = stmt.executeQuery("SELECT * FROM sampling_data d"
            + " WHERE EXISTS(SELECT * FROM entities e WHERE e.id = d.id)");
        List<Entity> entities = new ArrayList<Entity>();
        while (result.next()) {
            Entity entity = EntityFactory.createById(result);
            entities.add(entity);
        }
        result.close();
        stmt.close();
    } catch (SQLException ex) {
        Logger.getLogger(Test1.class.getName()).log(Level.SEVERE, null, ex);
    }

// EntityFactory
public static Entity createById(ResultSet resultSet) {
    EntityData data = new EntityData(25);
    for (int sample = 1; sample <= 25; sample++) {
        String sample_R = new StringBuilder("sample_").append(sample).append("_R").toString();
        String sample_G = new StringBuilder("sample_").append(sample).append("_G").toString();
        String sample_B = new StringBuilder("sample_").append(sample).append("_B").toString();
        int r = resultSet.getInt(sample_R);
        int g = resultSet.getInt(sample_G);
        int b = resultSet.getInt(sample_B);

        data.add(r, g, b);
    }

    return new Entity(data);
}
于 2012-04-22T13:45:06.603 回答