2009-03-16 1 views
21

他のオブジェクトとの関係が多いオブジェクトの複数のインスタンスを取得する際に、パフォーマンス上の問題が発生しています。私は、MySQLとSpringとHibernateのJPA実装を使用しています。問題は、JPAクエリを実行するとき、Hibernateは自動的に他のテーブルに参加しないということです。これにより、n * r + 1個のSQLクエリが生成されます。ここで、nは取得されるオブジェクトの数であり、rはリレーションシップの数です。パフォーマンス重視のアプリケーションでHibernateを使用できますか?

例は、人は、住所に住んでいる多くの趣味を持っており、多くの国々を訪問しました:

@Entity 
public class Person { 
    @Id public Integer personId;  
    public String name;  
    @ManyToOne public Address address;  
    @ManyToMany public Set<Hobby> hobbies;  
    @ManyToMany public Set<Country> countriesVisited; 
} 

私はボブという名前のすべての人を取得するためにJPAクエリを実行し、100のボブスはである場合にはデータベース:

SELECT p FROM Person p WHERE p.name='Bob' 

Hibernateは301のSQLクエリにこれを変換します。

SELECT ... FROM Person WHERE name='Bob' 
SELECT ... FROM Address WHERE personId=1 
SELECT ... FROM Address WHERE personId=2 
... 
SELECT ... FROM Hobby WHERE personId=1 
SELECT ... FROM Hobby WHERE personId=2 
... 
SELECT ... FROM Country WHERE personId=1 
SELECT ... FROM Country WHERE personId=2 
... 

Hibernate FAQ(hereおよびhere)によれば、解決策は、クエリにLEFT JOINまたはLEFT OUTER JOIN (for many-to-many)を指定することです。だから今、私のクエリは次のようになります。

SELECT p, a, h, c FROM Person p 
LEFT JOIN p.address a LEFT OUTER JOIN p.hobbies h LEFT OUTER JOIN p.countriesVisited c 
WHERE p.name = 'Bob' 

これは動作しますが、複数のLEFT OUTERをする場合、Hibernateは間違って存在しない列を探しているのJOINがあるかどうバグがあるように表示されます。

could not read column value from result set: personId69_2_; Column 'personId69_2_' not found. 

バグの挙動はおそらくHibernate Core bug HHH-3636によって解決されているようです。残念ながら、この修正はリリースされたHibernate JARの一部ではありません。私はスナップショットビルドに対して私のアプリケーションを走らせたが、バグの挙動は依然として残っている。また、リポジトリの最新コードから自分自身のHibernate Core JARをビルドしましたが、バグの動作はまだあります。だから、おそらくHHH-3636はこれに対処していません。

このHibernateのパフォーマンスの制限は非常にイライラです。 1000個のオブジェクトを照会すると、1000 * r + 1個のSQL照会がデータベースに行われます。私の場合、私は8つの関係を持っているので、8001のSQLクエリが得られ、ひどいパフォーマンスが得られます。これに対する公式のHibernateの解決策は、すべての関係を残すことです。しかし、これは、バグの振る舞いのために複数の多対多の関係では不可能です。ですから、多対多の関係のために多対1の関係とn * r + 1の問合せに対しては左結合が残っています。 LEFT OUTER JOINの問題をHibernateバグとして提出する予定ですが、その間に私の顧客は合理的なパフォーマンスを持つアプリを必要としています。私は現在、バッチフェッチ(BatchSize)、ehcache、およびカスタムメモリ内キャッシュの組み合わせを使用していますが、パフォーマンスはまだかなり悪いです(5000オブジェクトを30秒から8秒に回復することが改善されました)。要点は、あまりにも多くのSQLクエリがデータベースにヒットしていることです。

私の質問は、テーブルがお互いに複数の関係を持っているパフォーマンス重視のアプリケーションでHibernateを使用できるかどうかです。私は、Hibernateがどのようにアドレスパフォーマンスを使用するのか聞いてみたいと思います。私はSQLを手書きするべきですか(これはHibernateを使う目的を幾分打ち負かします)?結合されたテーブルの数を減らすためにデータベーススキーマを標準化解除する必要がありますか?高速なクエリパフォーマンスが必要な場合は、Hibernateを使用しないでください。何か速いのですか?

+0

を私たちは、その後、15倍の速〜であることBatoo JPAをリリースしてきましたHibernateを実行し、JPA Spec%100を実装します。このプロジェクトの主な動機は3つすべてのJPA実装が単純に遅くなったことです。 JPAがはるかに高速になることを実現したので、Batoo JPAを開発しました。それを試してみてくださいhttp://batoo.jp –

答えて

11

あなたはよくある質問の全体を読めば、あなたのother questionに私の答えを参照してください、あなたはにリンク:

は、ベストプラクティスガイドに従ってください!すべてとマッピングがHibernate2で​​lazy = "true"を指定していることを確認してください(これはHibernate3の新しいデフォルトです)。 HQL LEFT JOIN FETCHを使用して、最初のSQL SELECTで取得する必要のある関連付けを指定します。

N + 1は、問題を選択回避する第二の方法は=「副選択」Hibernate3のにフェッチを使用することです。

まだわからない場合は、HibernateのマニュアルとHibernate in Actionを参照してください。

improving performanceのヒントを参照してください。あなたが結合に慎重でないなら、あなたはCartesian Product問題で終わるでしょう。

+0

ありがとう、私は今これを調べています –

+0

Subselectは素晴らしい、ありがとう。 –

+0

フェッチのデフォルトについて明確にするだけです。注釈を使用する場合、Hibernateは、多対1および1対1の関連付けがデフォルトでは熱心であり、コレクションはデフォルトでは怠惰であることを示すJPA仕様によって設定されたデフォルトの取得に従います。 –

3

あなたはコレクションの "参加" fetch strategyを試みましたか?バグが修正されるまでしばらく Bがかかりますどの A)bugrequestを提出し、回避策(パフォーマンスの低下や手書きのSQL)を使用する:あなたが休止状態の機能を必要とし、この機能にバグがある場合

0

は、次の2つのオプションがあります)バグ修正とテストとともにバグリクエストを提出してください。 (もちろん、バグ修正を使用し、バグリクエストとテスト部分をスキップすることもできます)。

7

"フェッチ"戦略の他に、休止状態のプロパティでバッチフェッチサイズを設定することもできます。これにより、1つずつではなくバッチでのクエリの結合が実行されます。あなたのappContext.xmlで

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
    ...  
    <property name="hibernateProperties"> 
     <props>   
      ... 
      <prop key="hibernate.default_batch_fetch_size">32</prop> 
     </props> 
    </property> 
</bean> 

ので、代わりの:

SELECT ... FROM Hobby WHERE personId=1 
SELECT ... FROM Hobby WHERE personId=2 

あなたが取得します:

SELECT ... FROM Hobby WHERE personId in (1,2,...,32); 
SELECT ... FROM Hobby WHERE personId in (33,34,...,64); 
関連する問題