У меня есть объект Hibernate, который состоит из многих других объектов, которые используются в приложении. Другие сущности, составляющие этот MainEntity, соединяются с помощью @ManyToOne и @JoinColumn. Этот класс MainEntity имеет 5 столбцов (@Column) и 7 используемых объектов @ManyToOne / @JoinColumn.
Мне кажется, что при получении всех этих классов MainEntity у меня возникают проблемы с производительностью. Мы хотим сериализовать MainEntity в JSON, а также другие связанные с ним сущности. Обратите внимание, что мы извлекаем не так уж много - всего менее 30.
Ниже приведен пример того, как выглядит класс вместе с моим методом findAll() для получения этих классов. Я знаю, что @ManyToOne - это EAGER по умолчанию, поэтому мне интересно, есть ли лучший способ получить все эти объекты, который проще в системе. Заранее спасибо.
@Entity(name = "MainEntity")
@Table(name = "main_entity")
public class MainEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
// Other @Columns defined here
@ManyToOne()
@JoinColumn(name = "entity_1_id")
private Entity1 entity1;
@ManyToOne()
@JoinColumn(name = "entity_2_id")
private Entity2 entity2;
@ManyToOne()
@JoinColumn(name = "entity_3_id")
private Entity3 entity3;
// ... and so on, for a total of 7 @ManyToOne() columns
}
Вот метод findAll(), который у меня есть:
final List<E> findAllOrdered(Class<E> clazz, Order order) {
final Session session = sessionManager.openNewSession();
try {
return session.createCriteria(clazz)
.addOrder(order)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
} finally {
sessionManager.closeSession(session);
}
}
Я обнаружил, что мне нужно добавить Criteria.DISTINCT_ROOT_ENTITY, потому что мы получали дублирующиеся результаты MainEntity, если у ребенка было несколько связанных с ним. Я подозреваю, что это большая часть моей проблемы с производительностью.
Вам не кажется, что все эти отношения ManyToOne влияют на производительность. Вроде их много. Кроме того, есть ли у них собственные отношения, которые нетерпеливо загружены?
Сколько запросов запускает метод findAll? Он не использует никакого соединения? Почему вы думаете, что это идеальное узкое место? И не хотите ли загружать ассоциации ManyToOne?
@CholNhial - да, я точно думаю, что они вызывают проблему, я просто не знаю, как лучше с этим справиться. У некоторых из этих отношений есть другие, более ЖЕСТКИЕ. Я не думал об этом.
@MadhusudanaReddySunnapu - он много запускает, я включил отладку SQL через Hibernate, и, похоже, он выполняет тонну вызовов left outer join. Я думаю, что моя проблема, на что указал Чол, заключается в том, что некоторые из сопоставленных взаимосвязей также активно загружают данные.
@ joshft91 Я бы предпочел по умолчанию делать ассоциации Ленивыми. И присоединяйтесь к ним в HQL / критериях, основанных на том, какую ассоциацию мы действительно хотим получить. Также перед этим посмотрите количество запускаемых SQL-запросов, действительно ли они требуются, настроены ли запросы и т.д., и, соответственно, выберите LAZY или EAGER.
@MadhusudanaReddySunnapu - есть ли хороший способ узнать, сколько SQL-запросов запускается? В настоящее время я могу просто включить отладку SQL, где отображается сам запрос, но есть ли какие-либо другие советы по отладке Hibernate, о которых мне следует знать? Я действительно думаю, что мне, возможно, придется переопределить эту находку, чтобы я получал только ту информацию, которую хочу, от отношений.
Первым делом нужно включить show_sql, как в mkyong.com/hibernate/…. Это было бы хорошей отправной точкой, и впоследствии вы можете настроить свои ассоциации на LAZY / EAGER, SELECT / JOIN / SUBSELECT и настроить эти запросы, запустив их из какого-либо редактора БД, заметив стоимость / время для запроса.




Если вы получаете нежелательный ответ и хотите отфильтровать, вы можете использовать @JsonIgnore
например:
@ManyToOne()
@JoinColumn(name = "entity_1_id")
@JsonIgnore
private Entity1 entity1;
Несколько советов для рассмотрения:
Подумайте о том, чтобы сделать ассоциации ленивыми по умолчанию, если вы действительно не хотите загружать все данные ассоциации и их ассоциации вместе с родителем.
Используйте JOIN в HQL / критериях в зависимости от того, какую ассоциацию мы действительно хотим получить, и глубины ассоциаций.
Или используйте EntityGraph, чтобы решить, какие ассоциации нужно получить.
Включите show_sql, так как это показывает количество SQL-запросов и точные SQL-запросы, которые запускаются в БД. Это было бы хорошей отправной точкой, и впоследствии вы можете настроить свои ассоциации на LAZY / EAGER, SELECT / JOIN / SUBSELECT в зависимости от вашего варианта использования.
Вы можете запустить эти запросы к БД и посмотреть, поможет ли настройка запроса / БД (индексы, секционирование и т. д.) Сократить время запроса.
Посмотрите, поможет ли кеш второго уровня в вашем случае использования. Обратите внимание, что кэш второго уровня будет иметь свою сложность и дополнительные накладные расходы, особенно если данные относятся к транзакционному типу, а не только для чтения. Когда приложение развернуто на узлах, еще одним аспектом, о котором стоит подумать, станет сохранение согласованности кеша. Необходимо проверить, действительно ли дополнительные накладные расходы и сложность оправдывают эффективность кеш-памяти второго уровня.
С точки зрения дизайна приложения вы также можете подумать и посмотреть, действительно ли вы хотите получить MainEntity и ассоциации в одном запросе или пользовательском интерфейсе. Вместо этого мы могли бы сначала показать MainEntity с некоторым разбиением по страницам и на основе выбора мы могли бы получить ассоциации для этого MainEntity с помощью разбиения по страницам.
Обратите внимание, это не полный список. Но это хорошая отправная точка, и на основе вашего варианта использования вы можете увидеть, какой из них подойдет вам, а также любые другие дополнительные методы.
использовать кеш второго уровня Hibernate