1

オブジェクトを使用してScrollableResults、テーブルから約 500,000 から 1,000,000 行をスクロールしています。スクロールしながら、各反復の結果のエンティティを使用して別のエンティティを作成し、session.save()このオブジェクトを永続化するために使用します。以下はサンプル コードです。実際のコードはより複雑ですが、本質的に同じことを行っています。

Session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
ScrollableResults results = session.createQuery("from Foo_Table f join f.bars b")
    .scroll(ScrollMode.FORWARD_ONLY);
int i = 0;
while(results.next())
{
    Foo foo = (Foo) results.get(0);
    Bar bar = new Baz(foo);
    bar.setFoo(foo);

    session.save(bar)

    if(i % 50 == 0)
    {
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();

重要なエンティティ:

@Entity
@Table(name = "FOO_TABLE")
public class Foo_Entity implements Serializable {
    @Id    
    @Column(name = "Foo_ID", nullable=false)
    private String id;

    @OneToMany(fetch = FetchType.EAGER, //FetchType.LAZY fixes the slow down 
               mappedBy = "fooParent", cascade = CascadeType.ALL)
    private Set<Bar> bar_entities = new HashSet<>(0);
}

@Entity
@Table(name = "BAR_TABLE")
public class Bar_Entity implements Serializable {
    @Id
    @GeneratedValue
    @Column(name="Id")
    private Long id;

    @ManyToOne
    @JoinColumn(name="foo_pk")
    private Foo fooParent;

    // setFoo, getFoo...

}

このトランザクションの時間を計ると、実行時間は 500 回の反復ごとに約 100 ミリ秒で始まりますが、約 20,000 回の反復の後、500 回の反復ごとに数秒まで徐々に増加します。その結果、トランザクションのパフォーマンスが非常に低下します。時間がかかる唯一のコード行は、results.next()実行に時間がかかります。

この問題は、Foo の Bar エンティティのフェッチ タイプをeager からlazy に変更すると解決されます。まだ満たされていないセットに熱心なフェッチ タイプを使用すると、関係を含むエンティティのスクロールで問題が発生する理由がわかりません。確かに、session.flush() でのスクロール中にセットは満たされますが、私のシナリオでは、セットは通常 1 つから 2 つの要素だけで満たされます。

この特定のシナリオでこのスローダウンが発生する理由を知っている人はいますか?

この質問は、フェッチタイプを変更すると問題が解決することに気付く前に最初に投稿されたため、質問は「これを修正するにはどうすればよいですか」から「なぜこれが問題なのですか?」に移行したことに注意してください。

4

2 に答える 2

0

まず、フェッチが熱心な場合、つまり遅延読み込みが false の場合、Foo_Entity が読み込まれるたびに Bar_Entity が読み込まれます。したがって、クエリの結合を削除するか、フェッチを遅延させます。両方を持つことは冗長です。

第二に、スローダウンについて。ステートフル セッションを開いているためです。休止状態の第 1 レベル キャッシュにより、すべてのオブジェクトがメモリにキャッシュされます。このシナリオでは、スローダウンは怠惰、積極的、または結合とは何の関係もありません。スローダウンは、休止状態によってキャッシュ (メモリ) に保持されているオブジェクトの数が原因です。ステートレス セッションを使用してみてください。その後、スローダウンはなくなるはずです。下記URLをご参照ください

https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html

于 2015-07-02T05:37:35.907 に答える