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卻可以??磥鞧ROM對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 閱讀(2015) 評論(0)  編輯  收藏 所屬分類: Groovy & Grails
          主站蜘蛛池模板: 德庆县| 治多县| 元谋县| 武功县| 舟山市| 宜都市| 庆城县| 吴桥县| 鄂伦春自治旗| 泽州县| 齐齐哈尔市| 高安市| 桦南县| 宜兰市| 高清| 崇阳县| 阿巴嘎旗| 潼南县| 廊坊市| 庆元县| 来宾市| 湘潭县| 民勤县| 县级市| 保亭| 和顺县| 宁化县| 永兴县| 隆子县| 策勒县| 民丰县| 曲周县| 漳平市| 颍上县| 余干县| 绥芬河市| 海伦市| 砀山县| 苏尼特右旗| 新巴尔虎左旗| 南京市|