简体   繁体   中英

Why hibernate generates ~500 SQL queries?

When trying to optimize MySQ slow queries generated by Hibernate 4.2 in a legacy project, I found out that the code below generates nearly 500 SQL queries (with many duplicates) :

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;
    }
}

How can I avoid having so many SQL queries ?

I don't know if it helps but there are many onyToMany and manyToMany relationships between the entities.

Thank for your help.

You should check the queries hibernate is generating, to see which table is accessed frequently.

You have to join fetch entities related by your related entities as well, See here:

Hibernate is doing multiple select requests instead one (using join fetch)

I personally prefer lazy loading with an annotated @BatchSize() to keep the lazy-query-count small. Just using a Batch-Size of 2 will cut your query count in half then.

Also have a look at the @Cache Annotation which can reduce your query count in a significant way. (Just thinking of all the almost static stuff like city/building/type/domain and the like)

Depending on your relationship design, default value of Fetch in @OneToMany and @ManyToMany is LAZY , that means for loading related record in child entity (when you call getter method) hibernate executes one more query to load that record (for example: select * from foo where id = ? ) , so if loaded entity (main entity) contains many child entities such as ManyToMany or OneToMany you will see many queries in console. To void these queries, you can set Fetch to EAGER but this is not recommended on optimization.

@Entity
public class MainEntity {

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

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM