shinewang

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            53 隨筆 :: 0 文章 :: 200 評論 :: 0 Trackbacks

          使用ORM時,常常碰到N+1次查詢的問題。Hibernate采用立即加載(eager load)和延遲加載(lazy load)來解決這一問題,GROM建立在Hibernate的基礎之上,理論上同樣適用。但事實如何?

          Grails的官方文檔中提到:默認情況下,GORM 集合使用延遲加載的并且可以通過fetchMode來配置或者是使用mapping來配置 。并給出了一段在domain中配置的樣例代碼。

          但從我的使用經驗來看,不推薦在domain類中配置延遲加載。原因如下:
          1、在domain類中配置延遲加載是全局性的,有可能造成不需要開銷。
          2、目前在domain類中配置延遲加載存在Bug,只對one-to-many的關系才有效。

          例如論壇的列表頁面,需要顯示topic的分頁列表,其中每條topic需要顯示作者的名字,topic最后回復帖子的作者。

          按照官方文檔,可以在Topic類中如下配置,查詢結果為1條topic,理論上結果應該執行一條SQL語句:

          class ?Topic? {
          ????String?title
          ????String?body
          ????Date?createTime?
          = ? new ?Date()
          ????User?author
          ????Integer?viewNum?
          = ? 0
          ????Integer?postNum?
          = ? 0
          ????Date?lastUpdateTime
          ????User?lastUpdateBy
          ????
          static ?hasMany? = ?[?posts?:?Post?]
          ????
          static ?fetchMode? = ?[author: ' eager ' ,?lastUpdateBy: ' eager ' ]
          }

          但從SQL Log來看,Grails還是執行了3條SQL:

          select ?? from ?topic? where ?id = ?
          select ?? from ? user ? where ?id = ?
          select ?? from ? user ? where ?id = ?

          也就是說在domain類中配置延遲加載存在對one-to-one, many-to-one是無效的。

          如果這樣配置:

          class ?Topic? {
          ????String?title
          ????String?body
          ????Date?createTime?
          = ? new ?Date()
          ????User?author
          ????Integer?viewNum?
          = ? 0
          ????Integer?postNum?
          = ? 0
          ????Date?lastUpdateTime
          ????User?lastUpdateBy
          ????
          static ?hasMany? = ?[?posts?:?Post?]
          ????
          static ?fetchMode? = ?[posts: ' eager ' ]
          }

          執行Topic.get(id)來加載1條Topic,執行結果為1條SQL:

          select ?? from ?topic? left ? outer ? join ?post? on ?topic.id = posttopic_id? where ?topic.id = ?

          也就是說在domain類中配置延遲加載存在對one-to-many是有效的。以上結論對使用mapping來配置也是一樣的。

          這無疑是一個尷尬的結論,適用全局立即加載的author和lastUpdateBy不能在domain類中通過配置事先,不適用全局立即加載的posts卻可以。看來GROM對Hibernate的包裝還存在問題。

          目前的解決方法是不要在domain類中配置立即加載,而是在取數據的方法中按需要配置,例如Topic.list(fetch:[author:'eager', lastUpdateBy:'eager'])

          另外,可以參考一下這里關于立即加載和N+1次查詢性能的爭論。


          歡迎訪問我的blog: http://www.eoss.cn/blog/

          posted on 2008-11-26 16:06 shinewang 閱讀(2021) 評論(0)  編輯  收藏 所屬分類: Groovy & Grails
          主站蜘蛛池模板: 花莲市| 衡水市| 二手房| 扎鲁特旗| 临汾市| 南郑县| 黑龙江省| 津南区| 调兵山市| 广宁县| 台前县| 文登市| 思南县| 城口县| 华蓥市| 商城县| 灵宝市| 凌云县| 普兰县| 镇雄县| 弋阳县| 东源县| 绩溪县| 泰来县| 三河市| 枣强县| 杂多县| 万盛区| 屯昌县| 商城县| 古交市| 礼泉县| 景德镇市| 玛多县| 吴旗县| 宁夏| 乾安县| 高要市| 高陵县| 沧源| 喀喇|