Hibernateは、Hibernateが生成したselect文を最適化するためのフェッチ戦略をほとんど持たないため、可能な限り効率的です。

Hibernateが関連するコレクションとエンティティをフェッチする方法を定義するために、フェッチ戦略がマッピング関係で宣言されています。

フェッチ戦略

4つのフェッチ戦略があります

{空} 1。 fetch- “join” =遅延読み込みを無効にし、常にすべてのコレクションとエンティティを読み込みます。 2. fetch- “select”(デフォルト)=すべてのコレクションとエンティティを遅延ロードします。 3. batch-size = “N” = ‘N’コレクションまたはエンティティまでフェッチする、

記録しない

。 4. fetch- “subselect” =そのコレクションをサブ選択文にグループ化します。

詳細な説明については、https://www.hibernate.org/315.html[Hibernate documentation]を参照してください。

フェッチ戦略の例

ここでは、フェッチ戦略のデモンストレーションのための「1対多数の関係」の例があります。在庫は、多くの在庫日次記録に属します。


example XMLファイルでフェッチ戦略を宣言するため

...

<hibernate-mapping>
    <class name = "com.mkyong.common.Stock" table = "stock">
        <set name = "stockDayRecords" cascade = "all" inverse = "true"
            table = "stock__daily__record" batch-size = "10" fetch = "select">
            <key>
                <列名= "STOCK__ID" not-null = "true"/>
            </key>
            <one-to-many class = "com.mkyong.common.StockDailyRecord"/>
        </set>
    </class>
</hibernate-mapping>


exampleでアノテーションにフェッチ戦略を宣言するための例

...
@Entity
@Table(name = "stock", catalog = "mkyong")
public class Stock implements Serializable{
...

@OneToMany(fetch = FetchType.LAZY、mappedBy = "stock")
    @カスケード(CascadeType.ALL)
    @Fetch(FetchMode.SELECT)
        @BatchSize(サイズ= 10)
    public Set <StockDailyRecord> getStockDailyRecords(){
        これを返す.stockDailyRecords;
    }
...
}

フェッチ・ストラテジーがHibernateで生成されたSQLステートメントにどのように影響するかを見てみましょう。

1. fetch = “select”または@Fetch(FetchMode.SELECT)

これがデフォルトのフェッチ戦略です。それはすべての関連するコレクションの怠惰な読み込みを可能にしました。例を見てみましょう…​

…​.//call select from stock
Stock stock = (Stock)session.get(Stock.class, 114);
Set sets = stock.getStockDailyRecords();
//call select from stock

daily

record
for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
StockDailyRecord sdr = (StockDailyRecord) iter.next();
System.out.println(sdr.getDailyRecordId());
System.out.println(sdr.getDate());
}

__出力__

Hibernate:
select …​from mkyong.stock
where stock0

.STOCK

ID=?

Hibernate:
select …​from mkyong.stock

daily

record
where stockdaily0

.STOCK

ID=?

Hibernateは2つのselect文を生成しました

{空} 1。 Select文を使用してストックレコードを取得する -  **  session.get(Stock.class、114)**  2.関連するコレクションを選択する -  **  sets.iterator()**

===  2. fetch = "join"または@Fetch(FetchMode.JOIN)

「結合」フェッチ戦略は、関連するすべてのコレクションの遅延ロードを無効にします。例を見てみましょう...

....//call select from stock and stock__daily__record
Stock stock = (Stock)session.get(Stock.class, 114);
Set sets = stock.getStockDailyRecords();
//no extra select
for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}


出力

Hibernate:
    select ...
    from
        mkyong.stock stock0__
    left outer join
        mkyong.stock__daily__record stockdaily1__
            on stock0__.STOCK__ID=stockdaily1__.STOCK__ID
    where
        stock0__.STOCK__ID=?

Hibernateはselect文を1つだけ生成し、ストックが初期化されたときに関連するすべてのコレクションを取得します。

{空} 1。 Stockステートメントを取得するSelectステートメントと関連するコレクションを外部結合するステートメント

3. batch-size = “10”または@BatchSize(size = 10)

この ‘バッチサイズ’フェッチ戦略は、多くのHibernate開発者が常に誤解しています。

誤解

の概念を見てみましょう…​

Stock stock = (Stock)session.get(Stock.class, 114);
Set sets = stock.getStockDailyRecords();

for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}

あなたの期待する結果は何ですか、コレクションごとに10個のレコードを取得できますか?出力を参照してください

Output

Hibernate:
    select ...from mkyong.stock
    where stock0__.STOCK__ID=?

Hibernate:
    select ...from mkyong.stock__daily__record
    where stockdaily0__.STOCK__ID=?

バッチサイズはここでは何もしませんでした。バッチサイズの仕組みではありません。このステートメントを参照してください。

The batch-size fetching strategy is not define how many records inside
in the collections are loaded. Instead, it defines how many collections
should be loaded.

— Repeat N times until you remember this statement —

別の例

もう1つの例を見てみましょう。すべての株価記録とそれに関連する株式日次レコード(コレクション)を1つずつ印刷したいとします。

List<Stock> list = session.createQuery("from Stock").list();

for(Stock stock : list){

    Set sets = stock.getStockDailyRecords();

    for ( Iterator iter = sets.iterator();iter.hasNext(); ) {
            StockDailyRecord sdr = (StockDailyRecord) iter.next();
            System.out.println(sdr.getDailyRecordId());
            System.out.println(sdr.getDate());
    }
}

バッチサイズのフェッチ戦略はありません


出力

Hibernate:
    select ...
    from mkyong.stock stock0__

Hibernate:
    select ...
    from mkyong.stock__daily__record stockdaily0__
    where stockdaily0__.STOCK__ID=?

Hibernate:
    select ...
    from mkyong.stock__daily__record stockdaily0__
    where stockdaily0__.STOCK__ID=?

Keep repeat the select statements....depend how many stock records in your table.

データベースに20個のストックレコードがある場合、Hibernateのデフォルトのフェッチ戦略は20個のselectステートメントを生成し、データベースにヒットします。

{空} 1。 Select文を使用してすべてのStockレコードを取得します。
2.関連コレクションを選択する
3.関連コレクションを選択する
4.関連コレクションを選択する

21.関連するコレクションを選択する

生成されたクエリは効率的ではなく、重大なパフォーマンスを引き起こします
問題。

====== batch-size = '10 'フェッチ戦略を有効にしました。

batch-size = '10 'が有効な別の例を見てみましょう。
__出力__

休止状態:選択…​

mkyong.stock stock0から

休止状態:選択…​

from mkyong.stock

daily

record stockdaily0__ここで、(?、?、?、?、?、?、?、?、?、

さて、Hibernateはselect **  in ** を使ってコレクションをper-fetchします。
ステートメント。株式レコードが20件ある場合は、3つの選択肢が生成されます
ステートメント。

{空} 1。 Select文を使用してすべてのStockレコードを取得します。
2.関連するコレクションを個別にフェッチするためにIn文を選択します(10
コレクションは時間)
3.関連するコレクションを1つずつ取得するためにIn文を選択します(次の10
コレクションは時間)

バッチサイズを有効にすると、21からのselect文が単純化されます。
select文を3つのselect文に変更します。

=== 4. fetch = "subselect"または@Fetch(FetchMode.SUBSELECT)

このフェッチ戦略は、関連するすべてのコレクションをサブ
selectステートメント。再度同じクエリを見てみましょう..

リスト<Stock> list = session.createQuery( “from Stock”)。list();

for(株価:リスト){
            
    セットは= stock.getStockDailyRecords();
            
    for(Iterator iter = sets.iterator(); iter.hasNext();){
            StockDailyRecord sdr =(StockDailyRecord)iter.next();
            System.out.println(sdr.getDailyRecordId());
            System.out.println(sdr.getDate());
    }
}

__出力__

休止状態:選択…​

mkyong.stock stock0から

休止状態:選択…​

から
        mkyong.stock

daily

record stockdaily0

どこで
        在庫日時.

STOCK

ID in(
            選択する
                stock0

.STOCK

ID
            から
                mkyong.stock stock0

"subselect"を有効にすると、2つのselect文が作成されます。

{空} 1。 Select文を使用してすべてのStockレコードを取得します。
2.サブ選択クエリで関連するすべてのコレクションを選択します。

===結論

フェッチ戦略は非常に柔軟性があり、非常に重要な調整
Hibernateクエリを最適化するために使用しますが、間違った場所で使用した場合、
全災害になるでしょう。

===リファレンス

{空} 1。
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html
2. https://www.hibernate.org/315.html

link://タグ/hibernate/[hibernate]