web-dev-qa-db-ja.com

休止状態でのJOINとJOIN FETCHの違い

通常のJOINを使用する場所とJOIN FETCHを使用する場所を理解してください。

たとえば、次の2つのクエリがあるとします。

FROM Employee emp
JOIN emp.department dep

そして

FROM Employee emp
JOIN FETCH emp.department dep

違いはありますか?もしそうなら、いつどれを使うべきですか?

138
abbas

この2つのクエリでは、JOINを使用して、少なくとも1つの部門が関連付けられているすべての従業員をクエリしています。

ただし、違いは次のとおりです。最初のクエリでは、Hibernateの従業員のみが返されます。 2番目のクエリでは、関連付けられているすべての部署のEmployesを返しています。

そのため、2番目のクエリを使用する場合、各従業員の部署を確認するためにデータベースに再度アクセスするために新しいクエリを実行する必要はありません。

各従業員の部署が必要であることが確実な場合は、2番目のクエリを使用できます。部署が必要ない場合は、最初のクエリを使用します。

WHERE条件を適用する必要がある場合は、このリンクを読むことをお勧めします(おそらく必要になるでしょう)。 JPA 2 CriteriaQueryとして「where」句を使用してJPQL「join fetch」を正しく表現する方法?

更新

fetchを使用しないでDepartmentsが引き続き返されるのは、EmployeeとDepartmentの間のマッピング(@OneToMany)がFetchType.EAGERで設定されているためです。この場合、FROM Employeeを含む(fetchを含むまたは含まない)HQLクエリはすべてのDepartmentsを持ちます。すべてのマッピング* ToOne(@ManyToOneおよび@OneToOne)はデフォルトでEAGERです。

139
Dherik

このリンク 私はコメントで前述した、この部分を読む:

「フェッチ」結合を使用すると、単一の選択を使用して、関連付けまたは値のコレクションをその親オブジェクトとともに初期化できます。これはコレクションの場合に特に便利です。 これは、関連付けとコレクションについて、マッピングファイルの外部結合宣言と遅延宣言を効果的にオーバーライドします。

この "JOIN FETCH"は、エンティティ内のコレクションに対して(fetch = FetchType.LAZY)プロパティがある場合に効果があります(下記の例)。

そしてそれは「問い合わせが起こるべき時」の方法に影響するだけです。そして、あなたも知っておく必要があります this

休止状態には、2つの直交する概念があります。関連付けがいつ取得されるか、およびどのように取得されるかです。混同しないことが重要です。パフォーマンスを調整するためにフェッチを使います。 lazyを使って、特定のクラスの切り離されたインスタンスでどんなデータが常に利用可能かについての契約を定義することができます。

関連付けが取得されるタイミング - > "FETCH"タイプ

それはどのように取得されます - >参加/選択/副選択/バッチ

あなたの場合、FETCHはあなたがEmployeeの中にセットとして部門を持っている場合にのみ効果があります。

@OneToMany(fetch = FetchType.LAZY)
private Set<Department> department;

使うとき

FROM Employee emp
JOIN FETCH emp.department dep

empemp.depが表示されます。フェッチを使用しなかった場合でもemp.depを取得できますが、Hibernateはその部門のセットを取得するためにデータベースに対する別の選択を処理します。

そのため、パフォーマンスチューニングの問題であり、すべての結果を取得する必要があるか(必要であるかどうか)、または必要なときに後者でクエリを実行する(遅延フェッチ)必要があります。

1回の選択で小さなデータを取得する必要がある場合は、積極的なフェッチを使用してください(1つの大きなクエリ)。あるいは、遅延フェッチを使用して後者の必要なものをクエリします(多くの小さなクエリ)。

以下の場合にフェッチを使用します。

  • 大規模な不要なコレクション/そのエンティティ内に設定しようとしています

  • アプリケーションサーバーからデータベースサーバーへの通信が遠すぎ、時間がかかる

  • トランザクションのの外側(にアクセスできない場合は、後者のコレクションが必要になる可能性がありますメソッド/クラス)

55
Angga

@oneToOneマッピングがFetchType.LAZYに設定されていて、(Employeeオブジェクトの一部としてDepartmentオブジェクトを読み込む必要があるために)2番目のクエリを使用する場合、Hibernateの処理は、個々のEmployeeオブジェクトごとにDepartmentオブジェクトを取得するクエリを発行します。 DBから取得します。コードの後半で、Employee to Departmentの単一値関連を介してDepartmentオブジェクトにアクセスする可能性があり、Hibernateは特定のEmployeeのDepartmentオブジェクトを取得するためのクエリを発行しません。 Hibernateはまだ取得した従業員の数に等しいクエリを発行します。すべてのEmployeeオブジェクトのDepartmentオブジェクトにアクセスする場合、Hibernateは上記の両方のクエリで同じ数のクエリを発行します。

4
Bunti

Dherik:あなたが何を言っているのかよくわかりません、あなたがfetchを使わないとき、結果はタイプList<Object[ ]>になるでしょう。これはObjectテーブルのリストを意味し、Employeeのリストを意味しません。

Object[0] refers an Employee entity 
Object[1] refers a Departement entity 

Fetchを使用すると、選択は1つだけで、結果は部署のリストを含むEmployee List<Employee>のリストになります。エンティティの遅延宣言を上書きします。

2
Bilal BBB