当尝试在遗留项目中优化由Hibernate 4.2生成的MySQ慢查询时,我发现下面的代码生成了近500个SQL查询(包含许多重复项):
class MyDAO {
public List<Message> findMessages() {
Session session = MyHibernateUtils.openSession();
String queryStr = "SELECT DISTINCT m FROM Message m "
+ " LEFT JOIN fetch m.types types "
+ " LEFT JOIN fetch m.mainType mainType "
+ " LEFT JOIN fetch m.place place "
+ " LEFT JOIN fetch m.building building "
+ " LEFT JOIN fetch m.city city "
+ " LEFT JOIN fetch m.kind kind "
+ " LEFT JOIN fetch m.domain domain "
+ " LEFT JOIN fetch m.action action "
+ " LEFT JOIN fetch m.customParameterA customParameterA "
+ " LEFT JOIN fetch m.customParameterB customParameterB "
+ " LEFT JOIN fetch m.scheduleEvents scheduleEvents "
+ " LEFT JOIN fetch m.comments comments "
+ " LEFT JOIN fetch m.messageLastActivities messageLastActivities "
+ " LEFT JOIN fetch m.customListA customListA "
+ " LEFT JOIN fetch m.childEvents childEvents "
+ " LEFT JOIN fetch m.parentEvent parentEvent "
+ " WHERE ...";
List<Message> messages;
try {
session.getTransaction().begin();
Query query = session.createQuery(queryStr);
query.setTimeout(10);
messages = query.list();
session.getTransaction().commit();
} catch (RuntimeException e) {
session.getTransaction().rollback();
throw e;
} finally {
session.close();
}
return messages;
}
}
如何避免这么多SQL查询?
我不知道它是否有帮助,但实体之间有许多onyToMany和manyToMany关系。
感谢您的帮助。
答案 0 :(得分:1)
您应该检查hibernate正在生成的查询,以查看经常访问的表。
您必须join fetch
与related entities
相关的实体,请参阅此处:
Hibernate is doing multiple select requests instead one (using join fetch)
我个人更喜欢使用带注释的@BatchSize()
进行延迟加载,以使lazy-query-count保持较小。只需使用2的批量大小就可以将查询计数减半。
另请参阅@Cache
注释,它可以显着减少查询次数。 (只考虑所有几乎静态的东西,如城市/建筑/类型/域等)
答案 1 :(得分:0)
根据您的关系设计,Fetch
和@OneToMany
中@ManyToMany
的默认值为LAZY
,这意味着在子实体中加载相关记录(当您调用getter时)方法)hibernate再执行一个查询来加载该记录(例如:select * from foo where id = ?
),所以如果加载的实体(主实体)包含许多子实体,例如ManyToMany
或OneToMany
,你会看到控制台中的许多查询。
要取消这些查询,您可以将Fetch
设置为EAGER
,但不建议在优化时使用。
@Entity
public class MainEntity {
@ManyToMany(Fetch = FetchType.EAGER)
public List<Foo> foos;
}