數據庫設計
A 降低關聯的復雜性
B 盡量不使用聯合主鍵
C ID的生成機制不同的數據庫所提供的機制並不完全一樣
D 適當的冗余數據不過分追求高范式
HQL優化
HQL如果拋開它同HIBERNATE本身一些緩存機制的關聯HQL的優化技巧同普通的SQL優化技巧一樣可以很容易在網上找到一些經驗之談
主配置
A 查詢緩存同下面講的緩存不太一樣它是針對HQL語句的緩存即完全一樣的語句再次執行時可以利用緩存數據但是查詢緩存在一個交易系統(數據變更頻繁查詢條件相同的機率並不大)中可能會起反作用:它會白白耗費大量的系統資源但卻難以派上用場
B fetch_size同JDBC的相關參數作用類似參數並不是越大越好而應根據業務特征去設置
C batch_size同上
D 生產系統中切記要關掉SQL語句打印
緩存
A 數據庫級緩存:這級緩存是最高效和安全的但不同的數據庫可管理的層次並不一樣比如在ORACLE中可以在建表時指定將整個表置於緩存當中
B SESSION緩存:在一個HIBERNATE SESSION有效這級緩存的可干預性不強大多於HIBERNATE自動管理但它提供清除緩存的方法這在大批量增加/更新操作是有效的比如同時增加十萬條記錄按常規方式進行很可能會發現OutofMemeroy的異常這時可能需要手動清除這一級緩存:Sessionevict以及Sessionclear
C 應用緩存:在一個SESSIONFACTORY中有效因此也是優化的重中之重因此各類策略也考慮的較多在將數據放入這一級緩存之前需要考慮一些前提條件:
數據不會被第三方修改(比如是否有另一個應用也在修改這些數據?)
數據不會太大
數據不會頻繁更新(否則使用CACHE可能適得其反)
數據會被頻繁查詢
數據不是關鍵數據(如涉及錢安全等方面的問題)
緩存有幾種形式可以在映射文件中配置:readonly(只讀適用於很少變更的靜態數據/歷史數據)nonstrictreadwritereadwrite(比較普遍的形式效率一般)transactional(JTA中且支持的緩存產品較少)
D 分布式緩存:同c)的配置一樣只是緩存產品的選用不同在目前的HIBERNATE中可供選擇的不多oscache jboss cache目前的大多數項目對它們的用於集群的使用(特別是關鍵交易系統)都持保守態度在集群環境中只利用數據庫級的緩存是最安全的
延遲加載
A 實體延遲加載:通過使用動態代理實現
B 集合延遲加載:通過實現自有的SET/LISTHIBERNATE提供了這方面的支持
C 屬性延遲加載:
方法選用
A 完成同樣一件事HIBERNATE提供了可供選擇的一些方式但具體使用什麼方式可能用性能/代碼都會有影響顯示一次返回十萬條記錄(List/Set/Bag/Map等)進行處理很可能導致內存不夠的問題而如果用基於游標(ScrollableResults)或Iterator的結果集則不存在這樣的問題
B Session的load/get方法前者會使用二級緩存而後者則不使用
C Query和list/iterator如果去仔細研究一下它們你可能會發現很多有意思的情況二者主要區別(如果使用了Spring在HibernateTemplate中對應finditerator方法):
list只能利用查詢緩存(但在交易系統中查詢緩存作用不大)無法利用二級緩存中的單個實體但list查出的對象會寫入二級緩存但它一般只生成較少的執行SQL語句很多情況就是一條(無關聯)
iterator則可以利用二級緩存對於一條查詢語句它會先從數據庫中找出所有符合條件的記錄的ID再通過ID去緩存找對於緩存中沒有的記錄再構造語句從數據庫中查出因此很容易知道如果緩存中沒有任何符合條件的記錄使用iterator會產生N+條SQL語句(N為符合條件的記錄數)
通過iterator配合緩存管理API在海量數據查詢中可以很好的解決內存問題如:
while(ithasNext()){
YouObject object = (YouObject)itnext();
sessionevict(youObject);
sessionFactoryevice(YouObjectclass youObjectgetId());
}
如果用list方法很可能就出OutofMemory錯誤了
通過上面的說明我想你應該知道如何去使用這兩個方法了
集合的選用
在HIBERNATE 文檔的 Understanding Collection performance中有詳細的說明
事務控制
事務方面對性能有影響的主要包括:事務方式的選用事務隔離級別以及鎖的選用
A 事務方式選用:如果不涉及多個事務管理器事務的話不需要使用JTA只有JDBC的事務控制就可以
B 事務隔離級別:參見標准的SQL事務隔離級別
C 鎖的選用:悲觀鎖(一般由具體的事務管理器實現)對於長事務效率低但安全樂觀鎖(一般在應用級別實現)如在HIBERNATE中可以定義VERSION字段顯然如果有多個應用操作數據且這些應用不是用同一種樂觀鎖機制則樂觀鎖會失效因此針對不同的數據應有不同的策略同前面許多情況一樣很多時候我們是在效率與安全/准確性上找一個平衡點無論如何優化都不是一個純技術的問題你應該對你的應用和業務特征有足夠的了解
批量操作
即使是使用JDBC在進行大批數據更新時BATCH與不使用BATCH有效率上也有很大的差別我們可以通過設置batch_size來讓其支持批量操作
舉個例子要批量刪除某表中的對象如delete Account打出來的語句會發現HIBERNATE找出了所有ACCOUNT的ID再進行刪除這主要是為了維護二級緩存這樣效率肯定高不了在後續的版本中增加了bulk delete/update但這也無法解決緩存的維護問題也就是說由於有了二級緩存的維護問題HIBERNATE的批量操作效率並不盡如人意!
從前面許多要點可以看出很多時候我們是在效率與安全/准確性上找一個平衡點無論如何優化都不是一個純技術的問題你應該對你的應用和業務特征有足夠的了解一般的優化方案應在架構設計期就基本確定否則可能導致沒必要的返工致使項目延期而作為架構師和項目經理還要面對開發人員可能的抱怨必竟我們對用戶需求更改的控制力不大但技術/架構風險是應該在初期意識到並制定好相關的對策
還有一點要注意應用層的緩存只是錦上添花永遠不要把它當救命稻草應用的根基(數據庫設計算法高效的操作語句恰當API的選擇等)才是最重要的
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28234.html