隨筆-46  評論-54  文章-0  trackbacks-0

          同事在公司論壇里面發的,其實是我接手的一個項目中存在這個問題。
          在使用Hibernate分頁器時,習慣使用直接把查詢語句、頁數、分頁大小,傳給分頁器,這樣會默認使用last來獲取總記錄數,效率非常的低。
          解決方法,很簡單,就是用SQL來count查詢條件獲得總記錄的Query,再給Hibernate分頁器(本身就寫好了的)。
          這樣就必須多寫幾行代碼,就是因為自己懶,覺著效果都一樣,就簡單的寫了。
          數據量大了以后,就很明顯的速度慢下來了。又全部重頭改過,很是郁悶。
          轉載此文,以示提醒!
          即使懶得研究Hibernate底層,也要注意它的效率問題。

           

           

          我看到一些資料這樣說,oracle的jdbc驅動是不支持服務器端的游標的,當你調用resultSet.last()時,jdbc驅動程序會把整個結果集的數據讀到內存,然后在內存中進行結果集的遍歷。

          如果在做分頁的時候,用這樣的方式獲取結果的總記錄數:
            rs.last();
            int rowcount = rs.getRow();
          在結果集很大的時候,這個性能是相當低下的,并且會用掉很多的內存。

          這個問題是昨天在檢查人才網的代碼時發現的,隨著數據增加,原來被掩蓋的問題才開始暴露出來。我們用jprofiler對程序進行剖析的情況也間接的證明了上面的說法:1) 連續幾次刷新工作列表后,虛擬機的內存被占滿了,運行垃圾回收后內存又被釋放出來。2) 從頁面請求到完成響應,resultSet.last()方法的調用占去了cpu的絕大部分時間。

          因為上面提到的分頁方法是一種常用的方法,我建議大家考慮一下自己的代碼是否存在這樣的問題,這對辦公系統的穩定運行可能是很重要的。


          參考:
          http://www.oracle.com/technology/global/cn/sample_code/tech/java/codesnippet/jdbc/rs/CountResult.html
          提到了:
          如果 ResultSet 非常大,則 resultset.last() 有可能是非常費時的操作,因為它將使用服務器端的更多資源。因此,除非確實需要可滾動結果集,應避免使用這種方法。

          http://forum.springframework.org/showthread.php?t=50044&page=2
          提到了:
          Anyway, if it's a normal behaviour of the oracle driver to keep data in memory when using SCROLLABLE resultset

          http://xiongbo.javaeye.com/blog/38481
          對幾種游標類型做了介紹,并給出了建議

          posted on 2008-05-28 11:26 rox 閱讀(4195) 評論(4)  編輯  收藏 所屬分類: hibernate

          評論:
          # re: 開發者請注意oracle jdbc的resultSet.last()方法的效率問題【轉載】 2008-08-05 20:55 | tykon
          謝了。  回復  更多評論
            
          # re: 開發者請注意oracle jdbc的resultSet.last()方法的效率問題【轉載】 2008-08-20 15:11 | hello
          非常好,謝謝  回復  更多評論
            
          # re: 開發者請注意oracle jdbc的resultSet.last()方法的效率問題【轉載】 2009-03-12 17:27 | javakaifa
          解決方法是什么?  回復  更多評論
            
          # re: 開發者請注意oracle jdbc的resultSet.last()方法的效率問題【轉載】 2009-03-20 12:08 | rox
          @javakaifa
          HibernatePage
          http://www.hibernate.org/248.html

          protected static HibernatePage getScrollPageInstanceWithTotalByScroll(Query query, int pageNumber, int pageSize){
          ...
          sp.scrollableResults.last();
          sp.totalElements = sp.scrollableResults.getRowNumber();
          ...
          }
          追加一個方法,參數中支持把總數作為參數傳進來。
          protected static HibernatePage getScrollPageInstanceWithTotalByScroll(Query query, Integer totalCount, int pageNumber, int pageSize){
          ...
          if (totalCount != null)
          sp.totalElements = totalCount.intValue();
          else {
          sp.scrollableResults.last();
          sp.totalElements = sp.scrollableResults.getRowNumber();
          }
          ...
          }
          這個totalCount,使用相同查詢條件,只是查詢中使用count(*)來計算結果,并賦值給totalCount。
          也就是說同樣一個查詢,要做兩遍,一個是count,先做,再一個才是查詢。  回復  更多評論
            
          主站蜘蛛池模板: 阜城县| 通城县| 霍州市| 榕江县| 阜宁县| 浦县| 永靖县| 沂源县| 大石桥市| 云南省| 清水河县| 泸定县| 仁布县| 兴化市| 新野县| 长宁区| 松江区| 文水县| 扶余县| 科技| 武定县| 娄底市| 郴州市| 蓬溪县| 休宁县| 锡林浩特市| 聂拉木县| 周宁县| 梅河口市| 通州区| 遂宁市| 婺源县| 敦化市| 钟山县| 霍林郭勒市| 磐石市| 凤山县| 剑阁县| 东安县| 石阡县| 洛川县|