NHibernate性能調優之Lazy與Fetch

在應用開發中ORM(我用的是NHibernate)框架使用是否得當將直接影響到我們的程序的效率,其中的兩個概念:
  • lazy懶加載
  • select N+1問題
在性能調優中起到了至關重要的作用。

在以前我個人混亂的概念裏,啓用懶加載時,由於關聯對象要到需要的時候才查詢,所以sql會被拆分成兩次查詢。所以爲了解決select N+1問題,需要將lazy設置爲false。在實際開發使用中,這混亂的概念讓我吃了不少苦頭。

今日仔細測試發現,事實並非如此,lazy的設置只是決定了關聯信息的加載時間(一開始就加載還是需要時加載)。而是否使用關聯查詢是由fetch屬性決定
下面就讓我們看一下lazy與fetch兩個屬性組合使用的效果。使用兩個實體WallParam(參數)與WallParamGroup(參數組),其中關係爲多對一。
     
CASE 1:將lazy設爲proxy
<!--多對一關係-->
<many-to-onename="paramGroup"column="group_id"not-null="true"class="Model.WallParamGroup,Model"lazy="proxy"/>
當查詢WallParam信息時,lazy配置起作用了,執行的sql如下(沒有同時查出WallParamGroup, 該信息被延後了):
然而當執行查詢並同時獲取關聯的WallParamGroup信息時,nhibernate先後執行兩句sql來進行查詢:

結論:lazy的配置確實延後了關聯信息的加載,關聯信息只有被用的時候纔會去數據庫查詢。因此查詢語句也自然是拆分的sql。



CASE 2:此時已經將lazy設爲false
<!--多對一關係-->
<many-to-one name="paramGroupcolumn="group_idnot-null="trueclass="Model.WallParamGroup,Modellazy="false"/>
當查詢WallParam信息時,WallParamGroup的信息會同時加載出來。但是令人意外的是,執行的sql並不像我們認爲的是一句關聯查詢。而是任然執行了兩個拆分的sql,如下:

結論:lazy能延後關聯對象的數據加載,卻不能決定關聯數據的獲取方式(關聯查詢/拆分查詢)。因此僅僅使用lazy屬性並不能解決Select N+1問題。



CASE 3:保持lazy設爲false,同時將fetch設置爲join(fetch默認是“select”)
<!--多對一關係-->
<many-to-onename="paramGroup"column="group_id"not-null="true"class="Model.WallParamGroup,Model"lazy="false"fetch="join"/>
當查詢WallParam信息時,WallParamGroup的信息會同時加載出來。並且從生成的sql語句看,確實使用了關聯查詢,一句sql就取出了所有信息:

結論:設置fetch=“join”改變了查詢行爲,使得關聯對象能夠通過join查詢得到,從而解決了Select N+1問題。



CASE 4:那麼fetch設置爲join時,將lazy設爲proxy又會有什麼結果呢
<!--多對一關係-->
<many-to-onename="paramGroup"column="group_id"not-null="true"class="Model.WallParamGroup,Model"lazy="false"fetch="join"/>
當查詢WallParam信息時,WallParamGroup的信息會同時加載出來(這是因爲fetch指定了關聯查詢,所以關聯的WallParamGroup 信息已經被查詢出來,導致lazy失效)。並且從生成的sql語句看,確實使用了關聯查詢,一句sql就取出了所有信息:

結論:一旦設置fetch=“join”改變了查詢行爲(使用了關聯查詢),lazy懶加載就失去作用了(因爲關聯數據已經通過join查詢查出)。

總結:
  • lazy設置僅僅指明瞭關聯對象信息的加載時機(是一開始就加載,還是需要時加載)。
  • lazy加載只有在fetch=“select”(默認設置)時纔有效。
  • fetch設置能夠改變關聯對象信息查詢的行爲(通過關聯查詢還是拆分查詢)。
  • 解決Select N+1問題需要使用fetch=“join”。

所以個人認爲一種合理的做法就是,實體映射是保持fetch的默認設置(select),因爲只有這樣才能啓用懶加載。然後,當需要解決Select N+1問題以提高查詢效率的時候,在程序中使用如下代碼臨時改變查詢行爲:
ICriteria.SetFetchMode("WallParamGroup", FetchMode.Join)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章