1

データベースから約 6,000 万以上のレコードを選択する必要があるという要件があります。ResultSet にすべてのレコードを取得したら、クライアントの要件 (日付形式と数値形式) に従っていくつかの列をフォーマットする必要があり、すべてのレコードをファイル (セカンダリ メモリ) に書き込む必要があります。

  • 現在、DB から日単位でレコードを選択し (7 日間で 7 選択)、それらを HashMap に入れています。HashMap から読み取り、いくつかの列をフォーマットし、最後にファイル (7 日間の別のファイル) に書き込みます。
  • 最後に、7 つのファイルすべてを 1 つのファイルにマージしています。

  • しかし、このプロセス全体が完了するまでに 6 時間かかります。このプロセスを改善するために、7 日間で 7 つのスレッドを作成し、すべてのスレッドが別々のファイルを書き込んでいます。

  • 最後に、7 つのファイルすべてを 1 つのファイルにマージしています。このプロセスには 2 時間かかります。しかし、私のプログラムは1時間後にOutOfMemoryになります。

このシナリオに最適な設計を提案してください。キャッシュ メカニズムを使用する必要がありますか?

注: クライアントは、インデックスやストアド プロシージャの作成など、データベースで何も変更したくありません。データベースに触れたくありません。前もって感謝します。

4

4 に答える 4

4

それらをフォーマットするためにすべてのレコードをメモリに保持する必要がありますか? プロセスを介してレコードをストリーミングして、ファイルに直接送信することができます。クエリをさらに分割することさえできれば、結果を取得している間に結果の処理を開始できる可能性があります。

DB バックエンドによっては、Sql Server 2005+ 用の SSIS など、これを支援するツールがある場合があります。

編集

私は .net 開発者なので、.net で何をするかを提案させてください。Java 側で同等のテクノロジに変換できることを願っています。

ADO.Net には、結果セットの前方専用、読み取り専用 (Firehose) カーソルである DataReader があります。クエリの実行中にデータを返します。これはとても重要です。基本的に、私のロジックは次のようになります。

IDataReader reader=GetTheDataReader(dayOfWeek);

while (reader.Read())
{
    file.Write(formatRow(reader));
}

これは行を返している間に実行されるため、ネットワーク アクセスがブロックされないことが大きなボトルネックになると思います。ここで重要なのは、リーダーが結果を破棄し、ファイルが行をディスクに書き込むサイクルを繰り返すため、これをメモリに長時間保存しないことです。

于 2009-05-18T16:39:14.037 に答える
2

ジョシュが示唆しているのはこれだと思います:

現在、クエリのすべての結果レコードを通過するループがあります(ここでは疑似コードを使用しています):

while (rec = getNextRec() )
   {
   put in hash ...
   }

for each rec in (hash)
   {
   format and save back in hash ...
   }

for each rec in (hash)
   {
   write to a file ...
   }

instead, do it like this:

while (rec = getNextRec() )
   {
   format fields ...
   write to the file ...
   }

一度に複数のレコードがメモリに存在することはありません...そして無制限の数のレコードを処理できます。

于 2009-05-18T17:08:21.090 に答える
1

明らかに、一度に 6000 万件のレコードを読み取ることは、すべてのメモリを使い果たしているため、それを行うことはできません。(つまり、7 スレッド モデル)。一度に 6000 万件のレコードを読み取るのは、すべての時間を使い果たします。そのため、それもできません (つまり、ファイル モデルへの最初の読み取り)。

そのため、妥協して両方を少し行う必要があります。

Josh はそのとおりです。DB へのカーソルを開き、次のレコードを単純に、最も単純で機能が少ない方法で次々と読み取ります。"firehose" カーソル (読み取り専用、前方専用カーソルとも呼ばれます) は、データベースへの負荷が最小であるため、ここで必要なものです。DB では、レコードを更新したり、レコードセットをさかのぼったりすることはできません。これはいずれにしても望ましくないため、レコードのメモリを処理する必要はありません。

これで、このカーソルができました。DB から一度に 1 つのレコードが与えられます。それを読み取り、ファイル (または複数のファイル) に書き込みます。これは非常に迅速に終了するはずです。次に、ファイルを正しい順序で 1 つにマージする必要があります。これは比較的簡単です。

処理しなければならないレコードの量を考えると、これが最適なソリューションだと思います。

しかし...とにかく、これまでのところ非常にうまくやっているのを見て、メモリ制限内に収まるまでスレッドの数を減らしてみませんか. バッチ処理は夜通し行う会社が多いですが、これもその一つに過ぎないようです。

于 2009-05-18T17:39:08.407 に答える
0

使用しているデータベースにもよりますが、SQL Server の場合は、プログラムを作成するよりも SSIS などを使用することをお勧めします。

于 2009-05-18T16:36:22.840 に答える