У меня есть таблица «класс», которая связана с таблицами «ученик» и «учителя». «Класс» связан с несколькими учениками и учителями через внешние ключевые отношения.
Когда я использую ассоциации спящего режима и извлекаю большое количество объектов (пробовал для 5000), я вижу, что он занимает в 4 раза больше памяти, чем если бы я просто использовал держатели внешнего ключа. Что-то не так с ассоциацией спящего режима?
Могу ли я использовать любой профилировщик памяти, чтобы выяснить, что использует слишком много памяти?
Вот как выглядит схема:
class(id,className)
student(id,studentName,class_id)
teacher(id,teacherName,class_id)
class_id is foreign key..
Случай # 1 - ассоциации гибернации
1) в Entity класса отображены ученики и учителя как:
@Entity
@Table(name="class")
public class Class {
private Integer id;
private String className;
private Set<Student> students = new HashSet<Student>();
private Set<Teacher> teachers = new HashSet<Teacher>();
@OneToMany(fetch = FetchType.EAGER, mappedBy = "classRef")
@Cascade({ CascadeType.ALL })
@Fetch(FetchMode.SELECT)
@BatchSize(size=500)
public Set<Student> getStudents() {
return students;
}
2) у студентов и преподавателей класс отображается как:
@Entity
@Table(name="student")
public class Student {
private Integer id;
private String studentName;
private Class classRef;
@ManyToOne
@JoinColumn(name = "class_id")
public Class getClassRef() {
return classRef;
}
Используемый запрос:
sessionFactory.openSession().createQuery("from Class where id<5000");
Однако для этого требовалось огромное количество памяти.
Случай № 2 - Удалить ассоциации и получить отдельно
1) Нет сопоставления в сущности класса
@Entity
@Table(name="class")
public class Class {
private Integer id;
private String className;
2) Только местозаполнитель для внешнего ключа в учениках, учителях
@Entity
@Table(name="student")
public class Student {
private Integer id;
private String studentName;
private Integer class_id;
Использованные запросы:
sessionFactory.openSession().createQuery("from Class where id<5000");
sessionFactory.openSession().createQuery("from Student where class_id = :classId");
sessionFactory.openSession().createQuery("from Teacher where class_id = :classId");
Примечание. Показан только имп. часть кода. Я измеряю использование памяти извлеченными объектами через библиотеку JAMM.
Я также попытался пометить запрос как readOnly в случае №1, как показано ниже, что не сильно улучшает использование памяти; совсем немного. Так что решение не в этом.
Query query = sessionFactory.openSession().
createQuery("from Class where id<5000");
query.setReadOnly(true);
List<Class> classList = query.list();
sessionFactory.getCurrentSession().close();
Ниже приведены снимки дампа кучи, отсортированные по размеру. Похоже, что Entity, поддерживаемый спящим режимом, создает проблему.
Снимок Heapdump для программы ассоциаций гибернации
Снимок дампа кучи для выборки с использованием отдельных сущностей
from Student where class_id < 5000");
вместоfrom Student where class_id = :classId");
, чтобы отразить случай № 1 с отдельными запросами. То же самое относится и к запросу выбораTeacher
. Можете ли вы опубликовать наблюдения памяти с этими изменениями? - person Madhusudana Reddy Sunnapu   schedule 21.03.2016