2017-10-06 54 views
0

當試圖優化在傳統項目由Hibernate 4.2產生MySQ查詢速度慢,我發現下面的代碼生成近500 SQL查詢(許多重複):爲什麼hibernate會生成〜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

ORM框架大部分時間都是這樣工作的...他們需要額外啓動一個'SELECT * FROM table WHERE id = 1'找到相關的實體 –

+1

@RaymondNijland不,他們沒有。那麼,在最糟糕的情況下,他們會這樣做,但這在大多數情況下都是可以避免的,而且在Hibernate中也是如此。只有一個非常天真的ORM會這樣做,因爲它會導致性能下降,並使框架變得毫無價值。 – Kayaman

+0

至於OP,爲Hibernate啓用SQL日誌記錄(環顧四周,我不記得它是如何完成的),並查看*執行了哪些*查詢。這將允許您指出原因,這可能只是您需要修復的單個N + 1查詢。 – Kayaman

回答

1

您應該檢查hibernate正在生成的查詢,以查看經常訪問哪個表。

你必須join fetchrelated entities相關以及實體,在這裏看到:

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

我個人更喜歡懶加載帶有註釋@BatchSize()保持懶查詢算小。只使用2的批量大小將會減少一半的查詢次數。

也可以看看@Cache註解,它可以顯着減少查詢數量。 (只考慮像城市/建築/類型/域等所有幾乎靜態的東西)

+0

正確!謝謝@dognose,在添加了一些缺少的相關實體之後,查詢的數量大大減少了。 –

0

根據您的關係設計,@OneToMany@ManyToManyFetch默認值是LAZY,這意味着加載相關紀錄子實體(當你調用getter方法)休眠執行一個以上的查詢來加載記錄(例如: select * from foo where id = ?),所以如果加載實體(主實體)包含許多子實體,例如ManyToManyOneToMany,您將在控制檯中看到許多查詢。 要使這些查詢無效,可以將Fetch設置爲EAGER,但在優化時不推薦這樣做。

@Entity 
public class MainEntity { 

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

} 
+0

謝謝@Moodi您的迴應!使用'left join fetch'是不是已經迫使每個'* ToMany'依賴被急切地提取? –

+0

是的,它會獲取屬性。 – Antoniossss

+1

您可以使用子實體內的實體。 – Moodi