4

私の Web アプリケーションには、子との OneToMany 関係を持つオブジェクトがあります。オブジェクトを選択するときに、次のクエリを実行します。

from Object o

そして、私はすべてのオブジェクトについて、それが持っている子の数を出力する必要があります

// Foreach
object.children.size()

オブジェクトに多くの子があると仮定します (30,000 としましょう)。size() を呼び出すのはリソースの無駄ですか、それとも ORM フレームワーク (私の場合は Hibernate) がすべての子をロードせずにそれを処理しますか?

4

3 に答える 3

5

JPA(標準)の使用:

  • @OneToMany関係は、デフォルトで遅延読み込みされます(つまり、fetch = FetchType.LAZYのデフォルト値)。ただし、呼び出すEntity.getCollection().size()と遅延読み込みがトリガーされ、すべての子コレクションが取得されます。したがって、とにかくすべて/ほとんどの要素を操作する必要がない限り、かなり遅くなります。注:JPAのすべての(正常な)実装では、これは30,000の個別のクエリを発行しません。結果セットに30,000行を返す1つのクエリを発行します。
  • ほとんどの要素が必要な場合、または事前にキャッシュしたい場合は、@OneToMany(fetch=FetchType.EAGER)
  • すべてのオブジェクトを取得せずにデータ統計を取得する一般的な方法は、単にJPQL via EntityManager.getQuery()/getTypedQuery()/getNamedQuery()(またはSQL via getNativeQUery())を使用することです。これは非常にシンプルでパフォーマンスが高いです。
int empSize = em.createQuery("SELECT SIZE(d.employees) FROM Department d")     
                 .getSingleResult();    
OR ALTERNATIVELY

// Pre-compiled query placed against entity class for highest performance   
@NamedQueries({
    @NamedQuery(name="Department.EmployeeSize",
                query="SELECT SIZE(d.employees) FROM Department"),
    ... // other named queries
})
@Entity
public class Department {

    ...

}

// Then to use the query:    
int empSize = em.createNamedQuery("Department.EmployeeSize", Integer.class)     
                 .getSingleResult();    
  • レベル2のキャッシュを有効にできます。 JPAキャッシングの概要

    レベル2のキャッシュを静的に構成するには:

Map propertiesMap = new HashMap();
// Valid values are ALL, NONE, ENABLE_SELECTIVE, DISABLE_SELECTIVE
propertiesMap.add("javax.persistence.sharedCache.mode", "ENABLE_SELECTIVE");
EntityManagerFactory = Persistence.createEntityManagerFactory("myPUName", propertiesMap);
ALTERNATIVELY use persistence.xml:

<persistence-unit name="EmployeeService">
    ...
    <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

</persistence-unit>

次に、レベル2キャッシュに自動的にキャッシュするエンティティをマークします。

@Cacheable(true)
@Entity
public class Employee {
    ...
}
  • 特定のクエリの一部として、キャッシュを動的に構成することもできます

独自のアプローチを使用する(例:休止状態の「Extra-Lazy」コレクション):

  • 単にJPQL/SQLクエリを発行するのと同じパフォーマンス
  • 数行のコードを保存します(@ org.hibernate.annotations.LazyCollection(EXTRA)アノテーションv @NamedQueryアノテーションと実行)
  • 標準ではありません-JPAのトレーニングを受けた開発者はそれについて知りません
  • ポータブルではありません-そのベンダーでのみ使用できます。独自の機能から離れて、標準のJPAに向かう業界の傾向があります。多くの異なるJPA実装があります。
于 2012-11-02T23:01:52.367 に答える
2

JPA 実装でログ メッセージを有効にして、どの DB クエリが実際に DB に送信されるかを確認することをお勧めします。あなたの場合、ORMはおそらくすべてのオブジェクトを遅延ロードするので、非常に非効率的です。

于 2012-10-31T11:41:12.783 に答える
1

Hibernate には、まさにあなたが提案したことを実行する「extra lazy」コレクションと呼ばれる特別な機能があります。つまり、これらの超遅延コレクションのいずれかを呼び出すとsize()、コレクションが既に初期化されている場合はメモリ内の子の数が返されますがcount、コレクションがまだ初期化されていない場合はデータベースにクエリが実行されます。その意図は、絶対に必要になるまで非常に大きなコレクションを初期化することを避けることです。超怠惰が行う他の例には、Collection.contains/Map.containsKey呼び出し、Map.get呼び出し、List.get(int)などの呼び出しの処理が含まれます。

あなたが言う注釈でコレクションを超怠惰としてマークするには@org.hibernate.annotations.LazyCollection( EXTRA )

于 2012-11-01T12:10:12.603 に答える