0

Java OutOfMemoryError に問題があります。このプログラムは基本的に、mysql ワークベンチで実行されている mysql テーブルを調べ、クエリを実行して特定の情報を取得し、CSV ファイルに入れます。

プログラムは小さなデータ セットでは問題なく動作しますが、大きなデータ セットを使用すると (おそらく 40 分ではなく、何時間もの情報をログに記録する必要があります)、このエラーが発生します。これは、問題が巨大なデータ セットを持つことに起因することを示しています。また、情報がプログラムによって適切に処理されていません。または、私が持っている方法でこの量のデータを処理することは不可能です.

Java VM 引数を -xmx1024m に設定すると、わずかに大きなデータセットで機能しましたが、さらに大きなデータセットを処理する必要がありますが、エラーが発生します。

これは、プログラムのどこかの原因であると確信している方法です。

// CSV is csvwriter (external lib), sment are Statements, rs is a ResultSet
public void pidsforlog() throws IOException
{
    String[] procs;
    int count = 0;
    String temp = "";

    System.out.println("Commence getting PID's out of Log");
    try {
        sment = con.createStatement();
        sment2 = con.createStatement();
        String query1a = "SELECT * FROM log, cpuinfo, memoryinfo";
        rs = sment.executeQuery(query1a);
        procs = new String[countThrough(rs)];

        // SIMPLY GETS UNIQUE PROCESSES OUT OF TABLES AND STORES IN ARRAY
        while (rs.next()) {
            temp = rs.getString("Process");

            if(Arrays.asList(procs).contains(temp)) {
            } else {
                procs[count] = temp;
                count++;
            }
        }

        // BELIEVE THE PROBLEM LIES BELOW HERE. SIZE OF THE RESULTSET TOO BIG?
        for(int i = 0; i < procs.length; i++) {
            if(procs[i] == null) {
            } else {
                String query = "SELECT DISTINCT * FROM log, cpuinfo, memoryinfo WHERE log.Process = " + "'" + procs[i] + "'" + " AND cpuinfo.Process = " + "'" + procs[i] + "'" + " AND memoryinfo.Process = " + "'" + procs[i] + "'  AND log.Timestamp = cpuinfo.Timestamp = memoryinfo.Timestamp";
                System.out.println(query);
                rs = sment.executeQuery(query);

                writer = new CSVWriter(new FileWriter(procs[i] + ".csv"), ',');
                writer.writeAll(rs, true);
                writer.flush();
            }
        }
        writer.close();
    } catch (SQLException e) {
        notify("Error pidslog", e);
    }
}; // end of method 

この問題を解決したくてたまらないので、ソース コードや詳細情報が必要な場合はお気軽にお問い合わせください。

ありがとう。

4

5 に答える 5

2

SELECT * FROM log, cpuinfo, memoryinfo確かに巨大な結果セットが得られます。3 つのテーブルすべてのすべての行のデカルト積が得られます。

テーブル構造を確認せずに (または目的の結果を知らずに) 解決策を特定するのは困難ですが、何らかの結合条件で結果セットを制限するか、UNIONa'la;を使用する必要があるのではないかと思います。

SELECT Process FROM log
UNION
SELECT Process FROM cpuinfo
UNION
SELECT Process FROM memoryinfo

Process...これにより、3 つのテーブルすべての個別の値がすべて得られます。

2 番目の SQL ステートメントも少し奇妙に見えます。

SELECT DISTINCT * 
FROM log, cpuinfo, memoryinfo 
WHERE log.Process = @param1  
  AND cpuinfo.Process = @param1
  AND memoryinfo.Process = @param1
  AND log.Timestamp = cpuinfo.Timestamp = memoryinfo.Timestamp

3 つのログすべてから同時に選択しようとしているようですが、別のデカルト積になってしまいます。期待どおりの結果セットが得られますか?

于 2013-02-08T14:19:37.530 に答える
1

LIMIT Estatementet を使用して、SQL クエリによって返される結果を制限できます。

例えば:

 SELECT * FROM `your_table` LIMIT 100

これにより、最初の 100 件の結果が返されます

SELECT * FROM `your_table` LIMIT 100, 200

これにより、100 から 200 までの結果が返されます。

明らかに、これらの値を反復処理して、データベース上のすべての要素を取得することができます。

于 2013-02-08T14:19:44.613 に答える
0

Java コードは、データベースがより効率的に実行できることを実行しています。query1a から、本当に必要なのは固有のプロセスだけのように見えます。select distinct Process from ...それを行うには十分なはずです。

次に、そのクエリで必要なテーブルを慎重に検討してください。log、cpuinfo、および memoryinfo が本当に必要ですか? Joachim Isaksson が述べたように、これはこれら 3 つのテーブルのデカルト積を返し、x * y * z 行 (x、y、z はこれら 3 つのテーブルのそれぞれの行数) と a + b + を返します。 c 列 (ここで、a、b、および c は、各テーブルの列数です)。それがあなたが望んでいること、または必要としているとは思えません。これらの固有のプロセスは、1 つのテーブル、または 3 つのテーブルの結合 (結合ではなく) から取得できると思います。

最後に、2 番目のループとクエリは基本的に結合を行っていますが、これもより適切で効率的にデータベースに残されています。

于 2013-02-08T14:29:43.827 に答える
0

メモリに同時にロードしているデータが多すぎると思います。この問題を回避できるように、SQL ステートメントでoffsetandを使用してみてください。limit

于 2013-02-08T14:19:21.647 に答える
0

他の人が言ったように、データを小さなチャンクで取得すると問題が解決する場合があります。これは、この問題について話しているスタックオーバーフローの他のスレッドの 1 つです: How to read all rows from huge table?

于 2013-02-08T15:00:22.033 に答える