私は毎日数百万件のレコードを含む非常に大きなテーブルを持っており、毎日の終わりに前日のすべてのレコードを抽出しています。私はこれを次のように行っています:
String SQL = "select col1, col2, coln from mytable where timecol = yesterday";
Statement.executeQuery(SQL);
問題は、このプログラムはすべての結果をメモリに取り込んでから処理するため、約 2 GB のメモリを消費することです。
設定してみましたStatement.setFetchSize(10)
が、OSからまったく同じメモリを消費するので、違いはありません。私はMicrosoft SQL Server 2005 JDBC ドライバーこのために。
クエリを実行して数行のみを表示し、下にスクロールするとさらに多くの結果が表示される場合に、Oracle データベース ドライバーのように結果を小さなチャンクで読み取る方法はありますか?
ベストアンサー1
JDBC では、このsetFetchSize(int)
メソッドは JVM からデータベースへのネットワーク呼び出しの数と、それに応じて ResultSet 処理に使用される RAM の量を制御するため、JVM 内のパフォーマンスとメモリ管理にとって非常に重要です。
本質的に、setFetchSize(10) が呼び出され、ドライバーがそれを無視している場合、おそらく次の 2 つのオプションしかありません。
- フェッチ サイズのヒントを尊重する別の JDBC ドライバーを試してください。
- 接続のドライバー固有のプロパティ (接続インスタンスを作成するときの URL および/またはプロパティ マップ) を確認します。
RESULT-SET は、クエリに応じて DB にマーシャリングされる行の数です。ROW-SET は、JVM から DB への呼び出しごとに RESULT-SET からフェッチされる行のチャンクです。これらの呼び出しの数と、処理に必要な RAM は、フェッチ サイズの設定によって異なります。
したがって、RESULT-SET に 100 行あり、フェッチ サイズが 10 の場合、すべてのデータを取得するために 10 回のネットワーク呼び出しが発生し、常に約 10*{行コンテンツ サイズ} の RAM が使用されます。
デフォルトのフェッチ サイズは 10 で、かなり小さいです。投稿されたケースでは、ドライバーがフェッチ サイズ設定を無視し、1 回の呼び出しですべてのデータを取得しているように見えます (大量の RAM が必要で、ネットワーク呼び出しが最小限で最適)。
実際に内部で起こっていることResultSet.next()
は、RESULT-SET から一度に 1 行ずつフェッチするわけではないということです。(ローカルの) ROW-SET からそれをフェッチし、ローカル クライアントで使い果たされると、サーバーから次の ROW-SET を (目に見えない形で) フェッチします。
この設定は単なる「ヒント」であるため、すべてはドライバーに依存しますが、実際には多くのドライバーとデータベースでこのように動作することがわかりました (Oracle、DB2、MySQL の多くのバージョンで検証済み)。