Я вижу проблемы с производительностью при извлечении нескольких экземпляров объектов, которые имеют много связей с другими объектами. Я использую реализацию JPA Spring и Hibernate с MySQL. Проблема в том, что при выполнении запроса 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 JOIN в этом случае Hibernate неправильно ищет несуществующие колонки:
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 для этого состоит в том, чтобы оставить все отношения. Но это невозможно с более чем одним отношением «многие ко многим» из-за поведения ошибки. Таким образом, я застрял с левыми объединениями для отношений «один к одному» и n * r + 1 запросов из-за отношений «многие ко многим». Я планирую представить проблему LEFT OUTER JOIN как ошибку Hibernate, но в то же время моему клиенту нужно приложение, которое имеет разумную производительность. В настоящее время я использую комбинацию пакетной выборки (BatchSize), ehcache и пользовательского кэширования в памяти, но производительность по-прежнему довольно плохая (улучшено извлечение 5000 объектов с 30 до 8 секунд). Суть в том, что слишком много запросов SQL попадают в базу данных.
Итак, мои вопросы, можно ли использовать Hibernate в приложениях с высокой чувствительностью, где таблицы имеют несколько взаимосвязей друг с другом? Мне бы хотелось услышать, как успешный Hibernate использует производительность адреса. Должен ли я вручную писать SQL (что несколько поражает цель использования Hibernate)? Должен ли я де-нормализовать мою схему базы данных, чтобы уменьшить количество объединенных таблиц? Должен ли я использовать Hibernate, если мне нужна быстрая производительность запросов? Есть что-то быстрее?
Мы выпустили Batoo JPA, что составляет ~ 15 раз быстрее, Hibernate и реализует JPA Spec% 100. Основная мотивация проекта заключалась в том, что все три реализации JPA просто замедляются. Поняв, что JPA может быть намного быстрее, мы разработали Batoo JPA. Дайте ему попробовать http://batoo.jp –