他のオブジェクトとの関係が多いオブジェクトの複数のインスタンスを取得する際に、パフォーマンス上の問題が発生しています。私は、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を使用しないでください。何か速いのですか?
を私たちは、その後、15倍の速〜であることBatoo JPAをリリースしてきましたHibernateを実行し、JPA Spec%100を実装します。このプロジェクトの主な動機は3つすべてのJPA実装が単純に遅くなったことです。 JPAがはるかに高速になることを実現したので、Batoo JPAを開発しました。それを試してみてくださいhttp://batoo.jp –