註:分析sql的方式比較多,還有根據優化器、sql執行計劃來分析。
SQL_TRACE能夠將sql執行的過程輸出到壹個trace文件裏面。
首先設置自己定義的trace文件的標識方便查找。
alter session set tracefile_identifier='mytest';
然後對當前會話啟動SQL_TRACE,最好不要壹直打開該開關,代價比較大。
alter session set sql_trace=true;
然後我們執行壹條sql語句。
最後關閉該開關的狀態。
alter session set sql_trace=false;
我們可以從目錄%ORACLE_BASE%/diag/rdbms/orcl/orcl/trace(11g版本的路徑,如果是10g的應該不壹樣)中
找到自己定義的trace文件。
原始的trace文件的可讀性不高,我們壹般使用oracle自帶的工具,tkprof來處理這個trace文件。我們可以查看tkprof的幫助。
tkprof orcl_ora_3820_mytest.trc out.txt
我們來看剛才生成的trace文件,頭部信息描述了tkprof 的版本以及報告中壹些列的含義,對於任何壹條sql語句,都應該包含Parse—sql分析階段,Execute—sql執行階段,Fetch—數據提取階段,橫向的列如圖所示,包含消耗cpu時間0.00秒,操作總耗時0.04秒,物理讀取了0個數據塊,沒有發生current方式的讀取(壹般在update會發生),壹***提取記錄1條。
Misses in library cache during parse: 0表示這是壹次軟分析(關於硬分析和軟分析下面會接著談到)
Optimizer mode: ALL_ROWS表示oracle的優化器模式為ALL_ROWS。這也就是前面提到的另外的分析方式優化器。
下面是sql執行的具體計劃,可以看到執行計劃選擇的是全表掃描。
經過處理以後的trace文件的確比較容易看明白,它有助於我們分析sql的性能問題。
下面我通過壹個trace實例來解釋壹下,為什麽OLTP系統中需要變量綁定機制。
當用戶和數據庫建立連接,並發送壹條sql語句以後,oracle會對該sql進行hash函數運算(hash算法提供了壹種快速存取數據的方法,它用壹種算法建立鍵值與真實值之間的對應關系,每壹個真實值只能有壹個鍵值,但是壹個鍵值可以對應多個真實值,以方便存取),得到壹個hash值,然後到***享池中尋找是否有匹配的hash值的sql存在,如果有,就直接使用該sql的執行計劃去執行sql。如果沒有,oracle就會認為這是壹條新的sql語句,然後按照語法分析,語義分析,生成執行計劃,執行sql這些步驟來執行最終把結果返回給用戶。這些步驟也被成為硬分析,可以想象,如果減少硬分析,能夠大大降低數據庫花費在sql解析上的資源開銷。
我們先執行壹條sql 1000次,比較綁定變量和不綁定變量的差異。得到結果以後,要計算實際的消耗,我們需要把OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS以及OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS的時間累計起來,前者表示數據字典表的相關的信息,包含權限控制等,後者表示sql所衍生出的遞歸sql語句的信息。可以看到綁定變量的,整條語句執行時間為0.22+0.02=0.24秒,CPU時間0.18+0.03=0.21秒,分析次數3次,執行次數1003次。而不綁定變量的時候,整條語句執行時間為0.28+1.29=1.57秒,CPU時間0.31+1.26=1.57秒,分析次數1002次,執行次數1003次。可見綁定變量的確能夠帶來更低的開銷。(如何設計數據庫中使用綁定變量也是和系統息息相關的,很多數據庫問題都是在設計以後就已經存在的)
應用級調優分析:
就通常所說的三層架構來說,中間件這壹層能夠起到壹個緩沖池的作用,如果並發用戶數到3000這個數量級的時候,中間件能夠控制不是所有的用戶都能直接連接到數據庫,當然這裏的程序會快速響應用戶請求,保證緩沖池的隊列等待不會很久。
對應用這壹級別的調優,主要集中在app程序,中間件的監控,集群配置等方面。如果是發現應用級別的問題,首先要分析是配置問題,還是程序本身的問題。如果並發用戶數很大,中間件的線程池最大值配置過小,會導致在請求隊列堆積,表現就是線程監控視圖中,請求的隊列堆積比較多,壹般可以調整線程池最大值來解決。我們來看看weblogic的監控視圖。
考慮到如果為每壹個請求都創建壹個新線程來處理的話,那麽我們難以在系統中實現足夠數量的線程。不受限制的創建線程可能耗盡系統資源,因此引入了線程池。線程池的思想是在進程開始時創建壹定數量的線程並將它們置入壹個池(pool)中,線程在這個池中等待工作。當服務器接收到壹個請求時,它就從池中喚醒壹個線程(如果有可用的線程),由它來處理請求。壹旦線程服務完畢,它就返回線程池等待後面的工作。
線程池利用已存在的線程服務請求要比等待創建壹個線程要快,並且線程池限制了線程的數量。
如果懷疑是程序的問題,我們壹般可以通過java自帶的工具來幫助分析,工具很多。這裏我主要提到壹個jdk1.6以後附帶的jvisualvm。
我們打開jdk1.6,找到並運行jvisualvm.exe。
我們發現應用程序分為本地,遠程兩部分。本地包含本地運行的java進程,遠程能夠通過配置連接到遠程服務器上的java進程。我們先啟動壹個tomcat。可以看到本地應用程序已經打開了壹個帶有tomcat以及進程標識id的菜單。雙擊打開。這裏我們壹般關心2個視圖。監視、線程。
其中監視視圖比較關心垃圾回收活動(顧名思義,回收那些在程序裏面不再使用到的內存空間),堆內存變化。如果在壓力測試過程中,堆內存變化是壹個逐漸上漲的趨勢,並且經過多次手動gc回收,還是保持這個趨勢,說明內存泄漏的可能性很大。如果猜測有內存泄漏,可以通過分析java的heap dump。JVM (java虛擬機)記錄下問題發生時系統的運行狀態並將其存儲在轉儲(dump)文件中。Heap dump就是這樣壹種文件形式。
線程視圖比較關心線程的當前執行狀態,這裏可以生成另壹種轉儲文件 Java dump。Java dump,也叫做 Thread dump,是 JVM 故障診斷中最重要的轉儲文件之壹。JVM 的許多問題都可以使用這個文件進行診斷,其中比較典型的包括線程阻塞,CPU 使用率過高,JVM Crash,堆內存不足,和類裝載等問題。其中線程阻塞更加常見。
原文轉自:/xuyubotest/article/details/8158241