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

最大の問題は(私が思うに)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 に答える
0

コードを垣間見るだけではわかりにくいですが、フェッチされる行が多すぎることに関係していると私は推測しています。

妥当な行数 (おそらく 100 ) でsetFetchSize(int rows)を使用する必要があります。Statement

    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 ビルダーと int を使ってそのようなことをしているのだろうか。これらの RGB 値を のような意味のあるオブジェクトにカプセル化しますjava.awt.Color

ここで話しているデータの量はどれくらいですか?

25*3*32*2500 ~ 5.7 MB

これは、それぞれ 75 個の整数値を持つ 2500 行では大した量ではありません。あなたのコードからは明らかでない何かが起こっています。

アップデート:

このコードでは、古典的な(n+1)クエリの間違いを犯しています。すべてのエンティティを取得し、それらをループして RGB 値を取得します。JOIN を実行して、それらを一度に戻すことをお勧めします。それはあなたのメモリの問題を説明していないかもしれませんが、それは問題です.

RGB 値を照会するときに、列名を繰り返し作成します。それはまったく無駄です。それらをstatic final String配列内のインスタンスにします。

于 2012-04-22T12:33:36.330 に答える