1

ユーザー固有の「イベント」情報を呼び出すmy sqlストアドプロシージャを呼び出すjava-spring-hibernate Webアプリケーションがあります。

結果セットをテキスト ファイルに書き込み、1 つの ftp サーバーに送信する必要があります。ヒープ サイズとして 4 GB のスペースが割り当てられています。これ以上のヒープ サイズを割り当てることはできません。ただし、ストアド プロシージャが大きな結果セットを返し、それをサーバー側から処理すると、ヒープ サイズの問題が発生します。

現在のコード:

1: ストアド プロシージャは大きな結果セットを返します (たとえば、数百万行)

2:リストにマッピングする

3: 各行をテキスト ファイルに書き込みます。単一のユーザーの場合、3 つのイベントのみを書き込みます。3 つ以上のイベントがある場合は無視します (mysql から電子メール ベースの並べ替えられた結果セットを取得していることに注意してください)。サーバー側で行う必要があるこのプロセス

4:結果セットのサイズが大きい場合にヒープサイズの問題が発生しました

擬似コード:

 Stored proc
    delete temp table if exist
     get public event  into temp1 table based on condition
     get non public event into temp2 table
     create new temp tabletemp 3 by joining temp1 and temp2 and join with user table with some condition and sort it
    return select * from temp3 sorted based on email

必要なすべてのインデックスを設定した後でも、サーバー側のコードを完了するには通常 20 分かかります

   1:Create File writer object
    2:call stored proc
    import javax.persistence.EntityManager;
    ...
    ..
    Query query = entityManager.createNativeQuery("CALL procName(param)");
    ....
    list = query.getResultList();
    ....
    for (final Object[] objects : evntList) {
                    final EvntDTO dto = new ExactTargetDailyMailDTO(
                            String.valueOf(objects[0]),
                            String.valueOf(objects[1]),....,....,);
    if dto.getEvntNAme() matches some condition(){
    //change event name and other params accordingly
    }
    eventList.add(dto);
    }
    ...
    for (int i = 0; i < eventList.size(); i++) {
    Dto dto = eventList.get(i);
    count=1;
    ...
    fileContent=dto.getEmail()+appendmore user info +dto.getEventInfo();

    while (i + 1 < eventList.size()
                            && dto.getEmail().equalsIgnoreCase(remindersList.get(i + 1).getEmail())) {
                    if (count < 3) {
                    ....
                   fileContent=fileContent+add next EventInfo 

                   }
    ...
    ..
                   bw.write(fileContent);
                    bw.newLine();

    }
bw.close();
fw.close();

誰かがこれを行うためのより良い計画を提案できますか?

このリストでさらに操作を行いたいので (イベントが 3 つ以上ある場合は無視するなど)、一度に 1000 または 100 000 のデータを取得してファイルに書き込み、プロセスを繰り返すことは考えられません。

誰かが私に設計してそれを行うためのより良い方法を提案できますか?

4

2 に答える 2

2

ステップ 2 をスキップ: リストに保存します。

そうすれば、ストリーミングされたすべてのResultSet を強制的にメモリに格納できます。

File を sql の前に開いてから、すべての rs.next () に対して行を書いた場合、一度にメモリ内にいくつかの行しかありません。

削除後に 3 つ以上のイベントがスキップされた場合。

また

3行のみを返すようにSQLを書き直してください(制限3を使用してください)-そうすれば、処理する大きな結果セットはありません

あなたのコードに関するいくつかの考え

これは、オブジェクトをリストに受け取る部分です。

for (final Object[] objects : evntList) {
                final EvntDTO dto = new ExactTargetDailyMailDTO(
                        String.valueOf(objects[0]),
                        String.valueOf(objects[1]),....,....,);

  if(dto.getEvntName() matches some condition(){
  //change event name and other params accordingly
  }
  eventList.add(dto);

その後、そのリスト内のすべてのイベントを順番に繰り返し処理します。

for (int i = 0; i < eventList.size(); i++) {

リストに追加する代わりforに、ループで行うことを実行できない理由がわかりません。

次のエントリが最後のエントリと同じメールを持っているかどうかを確認する部分-現在のアイテムがのアイテムと同じ値を持っているかどうかを調べるために、それを逆にすることができるはずです。そうすれば、リストで「先をのぞく」必要はありません。

また、それらのメール アドレスに基づいてチェックを行っているようです。事前にremindersListの値を知っていれば、それをクエリの条件として使用できるはずです( AND email LIKE (?, ?, ?...)返される行数を減らす?

于 2015-12-19T10:05:53.823 に答える
0

ここで問題なのは結果セットではなく、コードです。リストを取り除き、結果取得ループ内で条件付き処理を行うだけです。そして、ファイルの内容に追加する部分を取り除き、延期するのではなく、毎回ファイルに直接書き込むだけです。

于 2015-12-19T22:45:56.203 に答える