5

私の問題は、OneToOneアソシエーションの休止状態の積極的な読み込みが、null関係ごとに+1selectを実行することです。

エンティティの例:

@Entity 
class SideBlue {
    @Column(nullable = false)
    private Integer timestamp;

    @OneToOne(optional=true) 
    @JoinColumn(name="timestamp", referenceColumn="timestamp", insertable = false, updatable = false) 
    SideRed redSide; 
}
@Entity 
class SideRed {
    @Column(nullable = false)
    private Integer timestamp;
}

(これはレガシーデータベーススキーマであるため、データベースの変更は許可されていません)

クエリの例:

CriteriaBuilder builder... CriteriaQuery query...
Root<SideBlue> root = query.from(SideBlue.class);
root.fetch(SideBlue_.sideRed, JoinType.LEFT);
entityManager().createQuery(query).getResultList();

結果:すべての青い側のエンティティに1つの赤い側がある場合、すべてが正しく実行されるため、Hibernateは、取得されるエンティティに対してデータベースに対して1つのクエリのみを実行します。

ただし、青い側のエンティティに赤い側のエンティティが関連付けられていない場合、休止状態はもう一度反対側を見つけようとします。Hibernate sqlコメントは、nullのredSideプロパティごとに「/*ロードRedSide* /select...」と言っています。

この2番目の選択をスキップするにはどうすればよいですか?

実際の問題は、レイテンシが極端に低くない場合に発生します。100万行を選択しようとして、1/3にヌルの「赤い面」がある場合、追加される合計レイテンシーは実際の問題です。

編集:

これはクエリのデバッグログです

10:04:32.812 [main] DEBUG org.hibernate.loader.Loader - Result set row: 0
10:04:32.815 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[SideBlue#1269721], EntityKey[SideRed#3620564]
10:04:32.833 [main] DEBUG org.hibernate.loader.Loader - Result set row: 1
10:04:32.833 [main] DEBUG org.hibernate.loader.Loader - Result row: EntityKey[SideBlue#1269776], null

最初の行には青と赤の面が含まれていますが、2番目の行には青の面のみが含まれています。したがって、休止状態は、関連する赤い面が存在しないことを知っている必要があります。しかし、すべての結果行が処理された後...

10:04:33.083 [main] DEBUG o.h.engine.internal.TwoPhaseLoad - Resolving associations for [BlueSide#1269721]
10:04:33.084 [main] DEBUG org.hibernate.loader.Loader - Loading entity: [RedSide#component[timestamp]{timestamp=1338937390}]
10:04:33.084 [main] DEBUG org.hibernate.SQL - /* load RedSide */ select ...
! Nothing really loaded because the previous SQL return empty result set, again !
10:04:33.211 [main] DEBUG org.hibernate.loader.Loader - Done entity load
4

1 に答える 1

1

さて、SideBlueのクエリを実行するときに、SideRedをロードしないようにしています。Hibernateからのこの「制限」に関連する遅延読み込みの問題だと思います(https://community.jboss.org/wiki/SomeExplanationsOnLazyLoadingone-to-one?_sscc=tから):

class B {  
    private C cee;  

    public C getCee() {  
        return cee;  
    }  

    public void setCee(C cee) {  
        this.cee = cee;  
    }  
}  

class C {  
    // Not important really  
}  

Bをロードした直後に、getCee()を呼び出してCを取得できます。ただし、getCee()はクラスのメソッドであり、Hibernateはそれを制御できません。Hibernateは、誰かがgetCee()をいつ呼び出すかを知りません。つまり、Hibernateは、データベースからBをロードするときに、適切な値を「cee」プロパティに入れる必要があります。

プロキシがCに対して有効になっている場合、HibernateはまだロードされていないCプロキシオブジェクトを配置できますが、誰かがそれを使用するとロードされます。これにより、1対1の遅延読み込みが可能になります。

しかし、ここで、BオブジェクトにCが関連付けられている場合と関連付けられていない場合があると想像してください(constrained = "false")。特定のBにCがない場合、getCee()は何を返す必要がありますか?ヌル。ただし、HibernateはBを設定した時点で「cee」の正しい値を設定する必要があることを忘れないでください(誰かがgetCee()をいつ呼び出すかわからないため)。プロキシ自体はすでにnull以外のオブジェクトにあるため、プロキシはここでは役に立ちません。

したがって、履歴書:B-> Cマッピングが必須(constrained = true)の場合、HibernateはCのプロキシを使用するため、初期化が遅延します。ただし、CなしでBを許可すると、HibernateはBをロードするときにCの存在をチェックする必要があります。ただし、同じSELECTが存在をチェックするだけでなく、オブジェクト全体をロードする可能性があるため、存在をチェックするSELECTは非効率的です。したがって、遅延読み込みはなくなります。

于 2014-03-16T20:53:42.563 に答える