为什么hibernate生成~500个SQL查询?

时间:2017-10-06 15:31:01

标签: java mysql hibernate

当尝试在遗留项目中优化由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关系。

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

您应该检查hibernate正在生成的查询,以查看经常访问的表。

您必须join fetchrelated 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 = ?),所以如果加载的实体(主实体)包含许多子实体,例如ManyToManyOneToMany,你会看到控制台中的许多查询。 要取消这些查询,您可以将Fetch设置为EAGER,但不建议在优化时使用。

@Entity
public class MainEntity {

@ManyToMany(Fetch = FetchType.EAGER)
public List<Foo> foos;

}