巨大なテーブルからすべてのレコードを取得するときに OOM (メモリ不足) エラーを回避するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/1107732

質問

巨大なテーブルをカスタム XML ファイルに変換するタスクが与えられました。この仕事には Java を使用します。

単純に「SELECT * FROM customer」を発行すると、大量のデータが返され、最終的に OOM が発生する可能性があります。レコードが利用可能になったらすぐに処理し、その後 SQL 取得プロセス中にメモリからレコードを削除する方法はあるでしょうか。

--- 2009 年 7 月 13 日に編集

私の質問を詳しく説明させてください。1 つのデータベースサーバーと 1 つのアプリケーションサーバーがあります。アプリケーションで選択クエリを発行すると、データはデータベースサーバーからアプリサーバーに転送されます。

ResultSet はクエリ内のすべてのレコードを受信するまで待機する必要があると思います (間違っている場合は修正してください)。1000 レコードのテーブルの場合、フェッチ サイズを 4 に設定したとしても、アプリ サーバーのヒープ メモリには 1000 レコードが残ることになりますが、正しいですか?フェッチ サイズは、データベース サーバーとの間の往復回数にのみ影響します。

私の質問は、アプリサーバーに到着した直後にその4つ(または任意の数)のレコードの処理を開始し、それを破棄してアプリサーバーのメモリを解放するにはどうすればよいですか?

役に立ちましたか?

解決

私はあなたのこの1と同じソリューションを使用することができると思いますに。スクロール可能な結果セットます。

他のヒント

もう少し情報を使用して、私はより有用な答えを得ることができます。

MySQLを使用している場合:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
       java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);

http://www.oracle.com/から技術/ハイテク/ javaの/ sqlj_jdbc / htdocsに/ jdbc_faq.htmlするます:

java.util.Properties info = new java.util.Properties();
info.put ("user", "scott");
info.put ("password","tiger");
info.put ("defaultRowPrefetch","15");
getConnection ("jdbc:oracle:oci:@",info);
あなたはJDBCを使用している場合は、

あなたは一度に一つのレコードを反復カーソルでResultSetを使用することができます。あなたは一度ではなくXMLを構築するためにDOMを使用するよりも、ファイル1つのレコードにあなたのXMLを書き出すことを、次に確認しますする必要があります。

私は私の経験から学んだ親指の一つのルールは、あなたのアプリケーションサーバにデータベースからすべてのデータを持ってないことです。あなたができることの一つは、あなたのデータページに手順を実装している。

あなたは再び、次のページのデータをフェッチ、それらを処理、1000から5000回の記録を中心に含むデータの1ページをもたらすことができます。

テーブル全体をエクスポートするための概念。 (専門家への注意:私はその欠点を承知しています。)

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
public class FullTableExport {
    public static String toXML(String s) {
        if (s != null) {
            StringBuilder b = new StringBuilder(s.length());
            for (int i = 0, count = s.length(); i < count; i++) {
                char c = s.charAt(i);
                switch (c) {
                case '<':
                    b.append("&lt;");
                    break;
                case '>':
                    b.append("&gt;");
                    break;
                case '\'':
                    b.append("&#39;");
                    break;
                case '"':
                    b.append("&quot;");
                    break;
                case '&':
                    b.append("&amp;");
                    break;
                default:
                    b.append(c);
                }
            }
            return b.toString();
        }
        return "";
    }
    public static void main(String[] args) throws Exception {
        String table = "CUSTOMER";
        int batch = 100;

        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection conn = DriverManager.getConnection(
            "jdbc:oracle:thin:@server:orcl", "user", "pass");
        PreparedStatement pstmt = conn.prepareStatement(
            "SELECT /*+FIRST_ROWS(" + batch + ") */ * FROM " + table);
        ResultSet rs = pstmt.executeQuery();
        rs.setFetchSize(batch);
        ResultSetMetaData rsm = rs.getMetaData();
        File output = new File("result.xml");
        PrintWriter out = new PrintWriter(new BufferedWriter(
            new OutputStreamWriter(
            new FileOutputStream(output), "UTF-8")), false);
        out.printf("<?xml version='1.0' encoding='UTF-8'?>%n");
        out.printf("<table name='%s'>%n", toXML(table));
        int j = 1;
        while (rs.next()) {
            out.printf("\t<row id='%d'>%n", j++);
            for (int i = 1; i <= rsm.getColumnCount(); i++) {
                out.printf("\t\t<col name='%s'>%s</col>%n", 
                    toXML(rsm.getColumnName(i)), 
                    toXML(rs.getString(i)));
            }
            out.printf("\t</row>%n");
        }
        out.printf("</table>%n", table);
        out.flush();
    }
}

編集 欠点 (@J.S. に感謝):

  • ojdbc 以外の外部ライブラリは使用されません
  • 何も閉まってないよ
  • 一般的な例外がスローされる
  • 主な方法です
  • XML 生成のための print の使用法
  • Oracle 固有の SQL
  • プレーンテキストのパスワード
  • 一部の列は文字列表現が不自然に見えます
  • UTF-8は国際的すぎる
  • XML 構造のフットプリントが大きい

OOMエラーが発生している段階では、XMLファイルへのデータの検索や処理データにある

そのデータ検索は、バッチでデータを取得する場合。 、最初の行の合計数を取得し、主キーによって選択を注文し、チュアブルサイズに選択された行を制限します。

そのXMLファイルを作成する時に、System.out.printlnは、各顧客のXMLノードを送信する場合は、

、メモリに保持しないでください。 commad回線を介してプログラムを起動し、ファイルへのすべての出力をリダイレクトする;

java MyConverter > results.txt

すべてがファイルに保存されたレコードを紹介ループとしてます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top