オブジェクトを使用して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 つの要素だけで満たされます。
この特定のシナリオでこのスローダウンが発生する理由を知っている人はいますか?
この質問は、フェッチタイプを変更すると問題が解決することに気付く前に最初に投稿されたため、質問は「これを修正するにはどうすればよいですか」から「なぜこれが問題なのですか?」に移行したことに注意してください。