示例2:錯誤的Hibernate配置造成了過多的SQL執行
據我所知,Hibernate或其他O/R映射器有許多使用者。我想要提醒你們一點,O/R映射器所提供的延遲加載與貪婪加載選項,以及其他各種緩存層各有其存在的理由。對于特定的用例,需要確保你正確地使用了這些特性與選項。
在下面這個示例中,延遲加載并不是一種好的選擇,因為加載2千個對象以及他們的屬性會導致產生4千多次SQL查詢??紤]到我們總是需要獲取所有對象,那么更好的方式是貪婪加載這些對象,然后考慮對他們進行緩存,前提是這些對象不會變更得十分頻繁:
(點擊放大圖像)
在使用Hibernate或Spring等O/R映射器時,需要選擇正確的加載與緩存選項。你需要理解他們的幕后工作原理。
大多數O/R映射器都會通過日志記錄提供優秀的診斷選項,同時也可以查看在線社區中的內容,以了解各種最佳實踐。推薦你閱讀由Alois Reitbauer撰寫的一系列博客文章,他曾經在Hibernate推出的早些年頭對其進行過非常深入的研究。在這系列文章中,他特別強調了如何有效地使用緩存與加載選項。
示例3:在自定義DB訪問代碼中使用的語句未經過預處理
當數據庫引擎完成對某條SQL語句的解析,并創建了數據訪問的執行計劃后,該結果會被保存在數據庫中的一個緩存區域中以便重用,而無需重新解析這一語句(語句解析是數據庫中最耗費CPU時間的操作)。用于在緩存中找到某個查詢的鍵是語句的全文本。這也意味著,如果你調用了1000次相同的語句,卻為其傳了100個不同的參數值(例如where語句中的值),那么在緩存中就會產生1000個不同的條目,而使用了新參數的第1001次查詢也必須被再次解析。這種工作方式非常低效。因此,我們提出了“預處理的語句”這一概念:某條語句經過預處理、解析后被保存在緩存中,以占位符的方式表示變量。在這條語句的實際執行過程中,這些占位符會被實際的值所替換,無需再次解析這條語句,可以直接從緩存中找出執行計劃。
數據庫訪問框架通常在這一點上做得很出色,會對查詢語句進行預處理。但在自定義代碼中,我發現開發者經常會忽略這一點。在以下示例中,只有一小部分SQL執行經過了預處理過程:
(點擊放大圖像)
通過對SQL執行次數與已預處理的SQL執行次數進行對比,發現了未經預處理的數據庫訪問的問題
如果你打算自行開發數據庫訪問代碼,請再次確認你正確地調用了prepareStatement。舉例來說,如果你調用某個查詢不止1次,那么通常來說最好能夠使用PreparedStatement。如果你選擇使用框架以訪問數據,也請再次確認這些框架的行為,以及在優化和執行所生成的SQL時有哪些配置選項可以選擇。實現一點最簡單的方式是對executeStatement與prepareStatement執行的次數進行監控。如果你重復對每個SQL查詢進行相同的監控,那么將很容易地找到優化熱點。
示例4:由于耗時的后端SQL報表執行,造成連接池無法有效地調整大小
我經常發現有些應用會使用默認的連接池大小,例如每個池10或20個連接。開發者總是會忽略對連接池大小的優化,因為他們沒有進行必要的大規模負載測試,也不知道有多少個用戶會使用這些新特性,更不了解并行的DB訪問會導致什么結果。也有可能是從預發布環境轉向生產環境的部署時“丟失”了連接池的配置信息,導致生產環境中的配置使用了應用服務器中的默認配置。
通過JMX指標信息,能夠方便地對連接池的使用情況進行監控。每種應用服務器(Tomcat、JBoss、Websphere等等)都會提供這些指標,不過有些服務器需要你明確地開啟這種特性。下圖展示了某個群集中的WebLogic服務器的連接池使用情況。你可以看到,在其中三臺應用服務器中, “活動的DB連接數量”都已經達到最大值。
(點擊放大圖像)
原文轉自:http://www.infoq.com/cn/articles/Diagnosing-Common-Java-Database-Performance-Hotspots