1. 程式人生 > >記一次通過v$active_session_history來分析問題的案例

記一次通過v$active_session_history來分析問題的案例

關於:v$active_session_history是oracle中一個最重要的檢視之一,該檢視每秒一次記錄當前資料庫中的活動程序相關的資訊,可以用於問題的分析和診斷;同時awr還會將部分v$active_session_history中的部分記錄保留到dba_hist_active_session_history(10秒一次),我們常用的ash報告就源於此。 通過v$active_session_history 檢視,可以看到資料庫中的活動程序在做什麼操作,以及是否有發生阻塞等情況,在分析和解決問題的時候可以從中獲取較多的資訊。

     以下案例是通過v$active_session_history分析當前某個生產庫問題發生的異常。

    首先是應用監控發現某個例項異常,應用伺服器上有連線報錯,從報錯看是連線db出現的問題。

    dba接到報警後,檢查相關的資料庫,發現當前已經恢復正常,確認應用恢復正常後,開始進行異常時間段的分析。

    這個問題需要從兩個方面分析:

      1、是應用負載增加,已有連線無法滿足,應用在不斷建立新的連線

      2、db中出現異常,程序出現阻塞,新的事務無法重用現有連線,導致db中不斷新建連線

    針對這個問題,我們首先分析了連線日誌,發現異常時間段確實有大量的新建連線。

但需要進一步分析是應用導致的還是db內部異常導致的。從應用負載看,並沒有明顯增加,問題集中在db當時是否出現異常等待。這個時候就需要從v$active_session_history分析(通常需要在發生異常後備份一次v$active_session_history,原因是v$ash的大小有限,如果不備份的話,後續分析時可能已經無法找到對應時間點的資料)。

1、首先需要確認異常的時間段 selectcount(*),sample_id,sample_time  fromv$active_session_history ash where ash.sample_time between $1 and $2 group bysample_id,sample_time order by sample_id; COUNT(*) SAMPLE_ID   SAMPLE_TIME   16       267491028   10-10月-17??01.40.01.180?下午 18       267491029   10-10月-17??01.40.02.192?下午 22       267491030   10-10月-17??01.40.03.195?下午 22       267491031   10-10月-17??01.40.04.209?下午 45       267491032   10-10月-17??01.40.05.221?下午 75       267491033   10-10月-17??01.40.06.233?下午 90       267491034   10-10月-17??01.40.07.246?下午 112       267491035   10-10月-17??01.40.08.259?下午 136       267491036   10-10月-17??01.40.09.296?下午 161       267491037   10-10月-17??01.40.10.309?下午 186       267491038   10-10月-17??01.40.11.322?下午 214       267491039   10-10月-17??01.40.12.336?下午 251       267491040   10-10月-17??01.40.13.350?下午 287       267491041   10-10月-17??01.40.14.364?下午 319       267491042   10-10月-17??01.40.15.379?下午 353       267491043   10-10月-17??01.40.16.393?下午 374       267491044   10-10月-17??01.40.17.408?下午 414       267491045   10-10月-17??01.40.18.423?下午 447       267491046   10-10月-17??01.40.19.440?下午 476       267491047   10-10月-17??01.40.20.456?下午 521       267491048   10-10月-17??01.40.21.472?下午 562       267491049   10-10月-17??01.40.22.489?下午 583       267491050   10-10月-17??01.40.23.507?下午 616       267491051   10-10月-17??01.40.24.552?下午 631       267491052   10-10月-17??01.40.25.570?下午 666       267491053   10-10月-17??01.40.26.589?下午 684       267491054   10-10月-17??01.40.27.609?下午 696       267491055   10-10月-17??01.40.28.629?下午 732       267491056   10-10月-17??01.40.29.649?下午 756       267491057   10-10月-17??01.40.30.672?下午 16       267491058   10-10月-17??01.40.31.693?下午 12       267491059   10-10月-17??01.40.32.707?下午 15       267491060   10-10月-17??01.40.33.719?下午

從面查詢的資訊中可以明顯看到活動程序在不斷的增加

2、確認異常時間段是否有異常的等待 select count(*),event   from v$active_session_history ash where ash.sample_id between267491028 and 267491060 group by event having count(*)>100    COUNT(*)  EVENT 322 10058     enq: TX - index contention

3、分析阻塞程序當前的操作(注:阻塞程序不一定都是活動程序,如果非活動程序的話,可能無法從v$active_session_history中查詢) 查詢4993程序在異常時間段內的操作,該程序未被其他程序阻塞(blocking_session為空),異常時間段內該程序的操作如下: selectash.sample_id,ash.sql_id,event,current_obj#,ash.current_file#,ash.current_block#,ash.session_state,ash.time_waited       from v$active_session_history ash      where sample_id between267491028 and 267491060        and sql_id = '38t8ff3k7t6g7'        and SESSION_ID = 4993      order by time_waited;       SAMPLE_ID   SQL_ID         EVENT                 CURRENT_OBJ# CURRENT_FILE# CURRENT_BLOCK# SESSION_STATE   TIME_WAITED      267491047   38t8ff3k7t6g7                                      224704        467          817769            ON CPU        0               267491054   38t8ff3k7t6g7                                      224704        490          1801532          ON CPU        0               267491050   38t8ff3k7t6g7 db file sequential read  224704        473          2058359          WAITING      222             267491034   38t8ff3k7t6g7 db file sequential read  224704        289          2561727          WAITING      229             267491037   38t8ff3k7t6g7 db file sequential read  224704        146          2872842          WAITING      244             267491052   38t8ff3k7t6g7 db file sequential read  224704        489          1789069          WAITING      259             267491043   38t8ff3k7t6g7 db file sequential read  224704        215          2928079          WAITING      260             267491035   38t8ff3k7t6g7 db file sequential read  224704        271          2630866          WAITING      282             267491046   38t8ff3k7t6g7 db file sequential read  224704        311          3216267          WAITING      1710            267491031   38t8ff3k7t6g7 db file sequential read  224704        281          2558211          WAITING      1749            267491042   38t8ff3k7t6g7 db file sequential read  224704        515          1070381          WAITING      1764            267491048   38t8ff3k7t6g7 db file sequential read  224704        822          2498767          WAITING      1778            267491039   38t8ff3k7t6g7 db file sequential read  224704        822          2512572          WAITING      1847            267491032   38t8ff3k7t6g7 db file sequential read  224704        472          2053998          WAITING      2380           

從上圖可以看到該語句是在做相同的insert操作,只是耗時比較久,io讀取都耗費在object_id為224704的物件上,這個物件就是表T_PUB_OVER_TIME_REC的主鍵 SQL> select object_namefrom dba_objects where object_id=224704; OBJECT_NAME -------------------------------------------------------------------------------- PK_OVER_TIME_REC_ID

SQL> selecttable_name,d.uniqueness from dba_indexes d where index_name='PK_OVER_TIME_REC_ID'; TABLE_NAME                     UNIQUENESS ---------------------------------------- T_PUB_OVER_TIME_REC            UNIQUE

4、分析異常  :為什麼insert操作中會在主鍵索引上有如此大量的io讀取呢? 首先要先了解在insert的時候為什麼會需要讀取索引塊:一個是正常的insert到對應的索引塊,另外一個就是索引分裂。 在insert操作的時候,在表和索引上的插入不是完全一致的,主要的原因就是索引的結構導致的,插入的索引值是有序的,需要從根節點開始尋找,找到對應的塊再插入,這個問題後續大家可以自行研究一下,但不會耗費太多的資源。 另外一種就是可能引發異常的情況,索引分裂引發的大量的io讀取,這個一般是在大量空塊的索引在做分裂的時候平衡二叉樹遍歷空塊導致的。 針對這個問題,需要去分析一下PK_OVER_TIME_REC_ID(單列索引)上是否有大量的空塊,實際上我們直接比對索引和表的大小就可以得出結論,表和索引幾乎已經1:1了,正常來說這種單列索引會比表小很多的,因此這個索引中空塊的問題是比較嚴重的,詳細的資訊可以通過analyzee等命令去分析索引塊的實際情況,但需要注意對於大索引來說會耗費比較多的時間和資源,不建議在生產庫直接執行。 SQL> select bytes/1024/1024 from dba_segments wheresegment_name='T_PUB_OVER_TIME_REC'; BYTES/1024/1024 ---------------            1249 SQL> select bytes/1024/1024 from dba_segments wheresegment_name='PK_OVER_TIME_REC_ID'; BYTES/1024/1024 ---------------            1193

5、問題解決方案

這個問題從oracle官方沒找到過明確的答覆和最終的解決方案,臨時方案是重建空塊過多的索引,但該方案不能從根本上解決問題,經過一段時間執行後問題會重複發生,比較理想的解決方案是應用修改資料刪除的方案,使用分割槽等。