:從快照機制到等待事件,DBA性能診斷全攻略)
簡介一份面向 Oracle 數(shù)據(jù)庫管理員與性能優(yōu)化人員的 AWR 報告分析指南由黃偉波撰寫系統(tǒng)講解 AWR自動工作負(fù)載庫從導(dǎo)出到分析的全流程。內(nèi)容涵蓋 AWR 概念、統(tǒng)計信息分類、STATISTICS_LEVEL 參數(shù)調(diào)優(yōu)、報告核心元素負(fù)載概況、SQL 報告、等待事件、活動會話歷史、AWR 維護(hù)與快照管理并演示通過企業(yè)管理器 EM 與命令行生成多種形式的報告基線對比、時段對比同時重點解讀緩沖區(qū)緩存命中率、硬解析次數(shù)、邏輯讀取次數(shù)等關(guān)鍵性能指標(biāo)幫助讀者定位瓶頸并優(yōu)化數(shù)據(jù)庫配置。整份資源為 1 個 PDF 文件大小 7.13MB內(nèi)容結(jié)構(gòu)按“導(dǎo)出 AWR 報告—分析 AWR 報告”組織目錄清晰既有基礎(chǔ)概念也包含操作性示例適合從初級到中高級的 DBA 閱讀與查閱。目前已有 225 人學(xué)習(xí)下載是一份偏理論但足夠完整的性能診斷參考手冊。 做DBA這些年我見過太多人拿到了Oracle數(shù)據(jù)庫的AWR報告翻了幾頁就擱到一邊嘴里念叨看不懂信息量太大不知道從哪里下手。尤其當(dāng)系統(tǒng)半夜出現(xiàn)性能問題第二天早上領(lǐng)導(dǎo)把一份幾百頁的HTML報告甩過來讓你給出結(jié)論時那種壓力我太熟悉了。AWRAutomatic Workload Repository自動工作負(fù)載信息庫報告說白了就是Oracle數(shù)據(jù)庫的行車記錄儀體檢報告。它每隔一段時間自動給數(shù)據(jù)庫拍一張快照記錄當(dāng)時的負(fù)載、等待事件、SQL執(zhí)行情況、資源消耗等關(guān)鍵指標(biāo)然后通過awrrpt.sql等腳本生成一份可讀的分析報告。這份報告的價值在于當(dāng)數(shù)據(jù)庫性能出現(xiàn)問題時它能告訴你過去這段時間數(shù)據(jù)庫到底在忙什么瓶頸卡在哪個環(huán)節(jié)哪些SQL是罪魁禍?zhǔn)?。本文就圍繞AWR報告分析這件事從一個一線DBA的實際視角把報告的生成、核心指標(biāo)解讀、根因反推方法以及我踩過的坑一次性講透。不管你是剛?cè)腴T的新手還是被性能問題折磨的老手這篇文章都能讓你拿到報告后不再發(fā)怵。1. 報告生成前必須搞清楚的事快照機制與生成方法1.1 AWR快照的工作機制AWR的核心機制是周期性采樣。默認(rèn)情況下Oracle每60分鐘自動采集一次快照Snapshot將數(shù)據(jù)庫的運行狀態(tài)寫入SYSAUX表空間中的WRM$_和WRH$_系列表里。這些快照數(shù)據(jù)默認(rèn)保留8天之后會被自動清理。所以你要分析某段時間的性能問題必須確??煺崭采w了問題發(fā)生的時間窗口。這里有一個常見誤區(qū)很多人直接把AWR等同于報告其實AWR是數(shù)據(jù)倉庫報告只是基于這些數(shù)據(jù)生成的分析視圖??煺詹杉臄?shù)據(jù)包括等待事件統(tǒng)計、時間模型統(tǒng)計、SQL執(zhí)行統(tǒng)計、會話活動統(tǒng)計、文件I/O統(tǒng)計、段Segment統(tǒng)計、系統(tǒng)參數(shù)快照等。知識點要記牢AWR報告對比的是兩個快照之間的增量數(shù)據(jù)而不是瞬時狀態(tài)。這意味著快照起點和終點的選擇直接決定了報告呈現(xiàn)的內(nèi)容。1.2 手動生成報告的完整步驟雖然默認(rèn)每60分鐘自動采集一次快照但實際生產(chǎn)中問題往往出現(xiàn)在兩次自動快照之間。所以手動創(chuàng)建快照、手動生成報告是DBA的基本功。生成單實例AWR報告的基本流程# 以sysdba身份登錄數(shù)據(jù)庫 sqlplus / as sysdba # 手動創(chuàng)建兩個快照可選一般建議分析已有快照 exec dbms_workload_repository.create_snapshot(); -- 等待一段時間讓負(fù)載數(shù)據(jù)被采集 exec dbms_workload_repository.create_snapshot(); # 調(diào)用報告生成腳本 ?/rdbms/admin/awrrpt.sql腳本執(zhí)行后會依次提示你輸入報告類型輸入html或text。我強烈建議選html因為HTML格式支持顏色標(biāo)注、排序點擊、圖表展示信息密度高且容易定位重點。除非你要做命令行環(huán)境下的快速分析才選text??煺仗鞌?shù)范圍輸入你要查看的時間跨度比如1表示查看最近1天的快照。起始快照ID和結(jié)束快照ID這里要注意起始ID必須小于結(jié)束ID且兩個ID之間的時間窗口要覆蓋問題時間段。輸出文件名默認(rèn)會生成awrrpt_1_100_101.html這樣的文件建議改成有意義的名字比如awrrpt_prod_20250117_2200_2300.html方便歸檔和追溯。如果是RAC集群環(huán)境每個實例有獨立的AWR數(shù)據(jù)你需要使用awrrpti.sql腳本并額外指定實例ID?/rdbms/admin/awrrpti.sql -- 按照提示輸入實例號比如 1 或 2這里分享一個我在實際運維中經(jīng)常用的小技巧分析跨實例的性能問題時最好分別生成每個實例的報告再做橫向?qū)Ρ取AC環(huán)境下負(fù)載不均衡的情況非常常見單看匯總報告容易掩蓋某個實例的異常。1.3 快照權(quán)限與歷史數(shù)據(jù)查詢不是所有數(shù)據(jù)庫用戶都有權(quán)限生成AWR報告。手動生成報告需要DBA角色或者被授予ADVISOR權(quán)限。如果使用的是云數(shù)據(jù)庫如阿里云RDS、AWS RDS權(quán)限往往受限你需要通過云平臺自帶的管理控制臺生成報告命令行的方式不一定可行。如果需要查看歷史快照信息可以查詢數(shù)據(jù)字典視圖-- 查詢數(shù)據(jù)庫現(xiàn)有的快照列表 select snap_id, instance_number, to_char(begin_interval_time, yyyy-mm-dd hh24:mi) as begin_time, to_char(end_interval_time, yyyy-mm-dd hh24:mi) as end_time from dba_hist_snapshot order by snap_id desc;通過這個視圖你可以快速定位哪個快照覆蓋了問題時間段避免盲目生成報告。我傾向于在生產(chǎn)系統(tǒng)出問題后第一時間先查快照列表確認(rèn)快照沒有缺失再決定是否需要手動補快照??煺杖笔У膯栴}我在后面專門講。2. 報告開篇三巨頭DB Time、Elapsed與負(fù)載畫像拿到AWR報告大多數(shù)人會從Report Summary開始看。這確實是正確入口但很多新手只是掃一眼就劃走了。實際上報告開頭這幾個指標(biāo)包含了大量信息值得逐項拆解。2.1 DB Time與Elapsed Time的關(guān)系這是AWR報告中最核心、最先要看的兩個數(shù)值Elapsed Time快照間隔的墻鐘時間即這段分析窗口實際過去了多久。DB Time數(shù)據(jù)庫實例在所有會話上花費的累計數(shù)據(jù)庫時間用戶調(diào)用消耗的CPU時間等待時間總和。注意它是累計值與并發(fā)會話數(shù)量直接相關(guān)。判斷邏輯很簡單如果DB Time遠(yuǎn)小于Elapsed Time說明數(shù)據(jù)庫大部分時間在休息負(fù)載較輕瓶頸大概率不在數(shù)據(jù)庫內(nèi)部。如果DB Time是Elapsed Time的幾倍甚至幾十倍說明數(shù)據(jù)庫內(nèi)部存在嚴(yán)重的爭用或等待CPU、I/O、鎖競爭必居其一。舉個例子某系統(tǒng)Elapsed Time為60分鐘DB Time為480分鐘說明平均有8個會話在同時干活。這時候你再看DB CPU與Total DB Time的占比如果CPU時間占比很低而等待時間占比很高就要重點看等待事件了。2.2 時間模型里的關(guān)鍵指標(biāo)AWR報告的Time Model Statistics部分按累計時間排序展示了數(shù)據(jù)庫各項操作的耗時占比。我通常關(guān)注這幾個指標(biāo)DB CPU所有會話消耗的CPU時間總和。CPU占比高說明數(shù)據(jù)庫在實打?qū)嵉赜嬎鉙QL執(zhí)行效率可能是關(guān)鍵。sql execute elapsed timeSQL執(zhí)行階段消耗的總時間。這個數(shù)值高說明SQL層是性能熱點。parse time elapsedSQL解析時間。如果這個占比異常高要考慮硬解析過多的問題往往與綁定變量使用不當(dāng)有關(guān)。connection management call elapsed time連接管理耗時。對高并發(fā)短連接應(yīng)用系統(tǒng)這個指標(biāo)會非常刺眼。時間模型看的是時間花到哪里去了它不像等待事件那樣能立刻指向資源瓶頸但能幫你確認(rèn)SQL執(zhí)行層在整個數(shù)據(jù)庫運行中的權(quán)重。看完整張報告后我通常會回到時間模型校驗一次自己的判斷。2.3 Load Profile系統(tǒng)負(fù)載的速寫畫像Load Profile部分展示的是每秒和每事務(wù)的平均指標(biāo)相當(dāng)于數(shù)據(jù)庫負(fù)載的速寫。這里不需要所有指標(biāo)都看但以下幾項要留意Redo size每秒產(chǎn)生的重做日志量。突然增大說明有大量DML操作或批量數(shù)據(jù)寫入。Logical reads與Physical reads邏輯讀反映SQL訪問的數(shù)據(jù)塊總量物理讀反映實際磁盤I/O量。物理讀占比過高通常意味著Buffer Cache命中率下降或全表掃描過多。Executes與Transactions每秒鐘執(zhí)行SQL次數(shù)與事務(wù)數(shù)。事務(wù)數(shù)是TPS的直接體現(xiàn)如果TPS暴跌結(jié)合其他指標(biāo)才能判斷是應(yīng)用問題還是數(shù)據(jù)庫問題。Hard parse每秒硬解析次數(shù)。數(shù)值長期偏高說明共享池使用效率差大量SQL沒有復(fù)用執(zhí)行計劃。Load Profile的意義在于建立基線。比如某系統(tǒng)平時每秒邏輯讀在300萬左右某天突然漲到900萬哪怕其他指標(biāo)還沒異常你也能嗅到SQL執(zhí)行計劃發(fā)生變化或數(shù)據(jù)量突增的味道。沒有基線所有數(shù)值都是孤立的有了基線變化本身就會說話。3. 等待事件分析定位瓶頸的核心抓手3.1 Top 10 Foreground Events的正確讀法AWR報告中最具診斷價值的部分我認(rèn)為是Top 10 Foreground Events by Total Wait Time。這部分按等待時間降序列出了前臺會話最關(guān)心的等待事件。解讀時要看三列Wait Time(s)、% DB Time、Wait Class。常見的等待事件分門別類說CPU時間類DB CPU被列在等待事件表格中它雖然不是等待但Oracle會把它排在前面。如果DB CPU排第一且占比超過30%說明數(shù)據(jù)庫瓶頸在CPU計算能力通常與低效SQL、全表掃描或排序操作過多有關(guān)。I/O類db file sequential read單塊讀常見于索引掃描、db file scattered read多塊讀常見于全表掃描或索引快速全掃描、direct path read直接路徑讀常見于并行查詢或排序。I/O等待占比高說明存儲性能或SQL訪問路徑出問題。并發(fā)類enq: TX - row lock contention行鎖爭用多會話更新同一行、enq: TM - contention表級鎖常見于DDL阻塞DML。日志類log file sync與log file parallel write。前者反映提交操作等待日志寫入磁盤的耗時對OLTP系統(tǒng)中提交頻繁的應(yīng)用影響極大。網(wǎng)絡(luò)類SQL*Net message from client這類等待說明數(shù)據(jù)庫在等客戶端發(fā)SQL過來通常不是數(shù)據(jù)庫瓶頸。不過如果在RAC環(huán)境中出現(xiàn)gc cr block busy這類集群互連等待就要考慮集群內(nèi)節(jié)點間通信效率問題。3.2 通過等待事件比例反推瓶頸只看等待事件名稱還不夠要結(jié)合% DB Time判斷嚴(yán)重程度。比如log file sync等待占總DB Time的25%意味著數(shù)據(jù)庫每4秒里就有1秒在等日志寫盤。此時回看Load Profile中的Redo size如果事務(wù)量并不大那問題可能在日志文件所在的存儲設(shè)備上如果事務(wù)量巨大則要考慮批量提交改批量、減少commit頻率等應(yīng)用層面的優(yōu)化。等待事件是并列關(guān)系而非因果關(guān)系這句話請劃重點。比如db file sequential read漲上來本質(zhì)可能是因為某個SQL走了低效的執(zhí)行計劃做了大量索引范圍掃描。等待事件是結(jié)果SQL才是原因。這也是為什么看等待事件之后永遠(yuǎn)要結(jié)合Top SQL去定位根因而不是停在資源層面。3.3 Instance Activity Stats補充閱讀Instance Activity Stats部分按統(tǒng)計項名稱展示快照期間的累計值。對于等待事件指向I/O時我建議順手查這幾個統(tǒng)計項physical reads和physical writes確認(rèn)I/O壓力是否真實存在。table scans (long tables)長表全表掃描次數(shù)這個數(shù)值如果大通常能和Top SQL中的全表掃描操作對得上。user commits與user rollbacks確認(rèn)提交頻率用于驗證日志類等待的推斷。session logical reads邏輯讀總次數(shù)是CPU消耗的重要影響因素。這些統(tǒng)計項未必每次都看但它們是驗證等待事件判斷的有力證據(jù)。分析AWR報告就像破案等待事件是現(xiàn)場線索實例統(tǒng)計是物證SQL是嫌疑人三者能彼此印證結(jié)論才站得住腳。4. SQL統(tǒng)計與段統(tǒng)計把根因釘死在SQL層面4.1 SQL ordered by Elapsed Time的結(jié)果解讀AWR報告的SQL Statistics部分按Elapsed Time、CPU Time、Physical Reads、Executions等多個維度展示Top SQL。我最常看的是SQL ordered by Elapsed Time和SQL ordered by CPU Time。這里有一個新手很容易踩的坑只看Elapsed Time排序容易忽略執(zhí)行次數(shù)極少的單次慢SQL也會把執(zhí)行次數(shù)多但單次很快的SQL當(dāng)作罪魁禍?zhǔn)?。比如某條SQL執(zhí)行了100萬次每次0.01秒累計Elapsed Time是10000秒排第一另一條SQL執(zhí)行了1次耗時3000秒排第二。從累計時間看第一條SQL更貴但從業(yè)務(wù)影響看第二條SQL直接堵住了前臺頁面用戶體感是系統(tǒng)卡死了。如果你只優(yōu)化第一條第二條的問題依然存在。我的習(xí)慣是優(yōu)先看Executions列區(qū)分高頻小SQL和低頻大SQL。對高頻SQL重點看單次執(zhí)行的邏輯讀和物理讀確認(rèn)是否有執(zhí)行計劃劣化。對低頻大SQL重點看是否做了不必要的全表掃描、排序或嵌套循環(huán)。SQL ordered by Physical Reads也需要盯住。物理讀高意味著大量磁盤I/O尤其是Physical Reads per Execution這個比值大時基本可以斷定SQL訪問路徑出了問題。這時候點開對應(yīng)的SQL文本和執(zhí)行計劃檢查索引情況多半能發(fā)現(xiàn)缺少索引或索引失效的問題。4.2 執(zhí)行計劃變化不只是看SQL文本拿到Top SQL后務(wù)必將本次AWR報告中的執(zhí)行計劃與SQL歷史執(zhí)行計劃做對比。AWR本身不直接保存執(zhí)行計劃歷史但可以借助dba_hist_sql_plan視圖查看-- 查看某條SQL語句在特定快照間的執(zhí)行計劃變化 select * from table(dbms_xplan.display_awr(sql_id, plan_hash_value));如果發(fā)現(xiàn)同一SQL_id在不同快照中Plan Hash Value不同說明執(zhí)行計劃變了。常見的導(dǎo)致執(zhí)行計劃變化的因素有表數(shù)據(jù)量增長、統(tǒng)計信息過期、綁定變量窺探Bind Peeking、參數(shù)變化。這時候要重點分析新執(zhí)行計劃到底差在哪個環(huán)節(jié)——是全表掃描替代了索引掃描還是Join順序改變導(dǎo)致中間結(jié)果集膨脹。4.3 Segment Statistics定位熱點對象Segment Statistics部分按邏輯讀、物理讀、緩沖區(qū)忙等待等維度列出熱點數(shù)據(jù)庫對象表、索引、分區(qū)。這部分能幫你快速建立SQL?對象的對應(yīng)關(guān)系。例如Segments by Logical Reads排名第一的表恰好是Top SQL中某條SQL訪問的表基本可以確定問題SQL和這個表的訪問方式有關(guān)。如果這個表邏輯讀極高但物理讀不高說明數(shù)據(jù)已經(jīng)被緩存在Buffer Cache中CPU壓力來自大量buffer cache的遍歷如果物理讀和邏輯讀雙高說明內(nèi)存放不下或者訪問路徑根本沒用上索引。Segments by Buffer Busy Waits也值得關(guān)注。如果某段頻繁出現(xiàn)buffer busy wait可能涉及熱點塊競爭——多個會話同時訪問同一個數(shù)據(jù)塊。這在某些全局唯一索引、序列或頻繁更新的小表上很常見。遇到這種情況有時候要改應(yīng)用邏輯比如減少對同一行的頻繁更新有時候要調(diào)整PCTFREE或分區(qū)設(shè)計單純調(diào)SQL未必有效。5. 從報告到結(jié)論一次完整的根因推演案例理論講了這么多我拿一個實際遇到的案例來串一遍這樣整個分析鏈路會更清晰。某業(yè)務(wù)系統(tǒng)反饋每天晚上8點到9點之間特別慢業(yè)務(wù)人員操作一個查詢頁面要等十幾秒。生成這段時間的AWR報告后我按如下順序做了分析第一步看DB Time vs Elapsed Time。Elapsed Time約60分鐘DB Time約350分鐘負(fù)載確實集中在這個時段。第二步看Top 10 Foreground Events排第一的是db file sequential read占比約45%其次是DB CPU占比約25%??吹竭@個組合我的第一判斷是大量單塊讀——極可能有人在通過索引做大量逐行訪問I/O等待拖慢了整體響應(yīng)。第三步回到Load Profile看Physical reads per second數(shù)值為平時基線的6倍進(jìn)一步確認(rèn)I/O壓力激增。第四步翻開SQL ordered by Physical Reads果然有一條SQL的物理讀次數(shù)遠(yuǎn)超其他SQL。點開SQL文本是一張大寬表的主鍵范圍查詢而執(zhí)行計劃顯示它走了索引全掃描Index Full Scan該索引的葉子塊數(shù)量超過3萬個。為什么走索引全掃描進(jìn)一步查執(zhí)行計劃發(fā)現(xiàn)查詢條件里用到了函數(shù)包裹索引列導(dǎo)致索引失效Oracle選擇了掃描整個索引然后做過濾。第五步驗證將該SQL改為在應(yīng)用層先計算函數(shù)結(jié)果、再以原始列值查詢或者建立函數(shù)索引物理讀從每分鐘2萬次直接降到幾百次頁面響應(yīng)恢復(fù)正常。這個案例說明AWR報告分析的真正價值在于層層遞進(jìn)交叉驗證。等待事件給方向Load Profile給量級Top SQL給抓手執(zhí)行計劃給根因。任何一步單獨看都可能誤判但串聯(lián)起來就是一個完整的故事。6. 實戰(zhàn)中的高頻坑快照缺失、RAC誤讀與報表陷阱6.1 快照缺失和采樣窗口問題分析AWR報告最容易翻車的情況恰恰是報告生成本身。我之前遇到過一個問題數(shù)據(jù)庫每天早上8點出現(xiàn)CPU飆高但生成的AWR報告里負(fù)載卻平平無奇。后來查了dba_hist_snapshot才發(fā)現(xiàn)8點前后恰好處于兩個自動快照之間的盲區(qū)——問題只持續(xù)了10分鐘而快照間隔是60分鐘峰值被平均掉了。解決辦法有兩個在問題高發(fā)時段提前部署手動快照縮小采樣窗口-- 每10分鐘生成一次手動快照連續(xù)生成6次覆蓋1小時 begin for i in 1..6 loop dbms_workload_repository.create_snapshot(); dbms_lock.sleep(600); end loop; end; /如果問題已經(jīng)發(fā)生且沒有留存高頻快照退而求其次分析ASHActive Session History報告。ASH按秒級采樣會話活動彌補AWR分鐘級粒度的不足。生成方式類似?/rdbms/admin/ashrpt.sql分析方法與AWR一脈相承重點看Top活動會話的等待事件和SQL_ID。6.2 RAC環(huán)境下單實例報告的局限RAC環(huán)境中最容易犯的錯是只生成某一個實例的AWR報告然后對整體性能下結(jié)論。例如兩個節(jié)點的負(fù)載嚴(yán)重不均衡節(jié)點1的DB Time是節(jié)點2的8倍你只看節(jié)點1的報告會認(rèn)為系統(tǒng)繁忙到崩潰只看節(jié)點2的報告會認(rèn)為系統(tǒng)閑得很。必須分別生成每個實例的報告同時對比Global Cache Statistics里的gc cr block receive time、ges messages sent等集群互連指標(biāo)才能判斷是否存在節(jié)點間通信瓶頸。RAC還有一個隱蔽問題同一個SQL在不同節(jié)點上的執(zhí)行計劃和性能可能完全不同。分析時需要按con_id和instance_number分開查看SQL在各自節(jié)點的表現(xiàn)。如果只拉匯總報告這些差異會被掩蓋。6.3 容易誤判的指標(biāo)陷阱最后列幾個我在實際工作中反復(fù)踩過的指標(biāo)陷阱Buffer Cache命中率陷阱命中率高不代表性能好。如果一個系統(tǒng)命中率99%但邏輯讀總量高達(dá)每秒500萬依然會消耗巨額CPU。高命中率掩蓋了低效SQL的大量邏輯訪問。所以命中率要結(jié)合邏輯讀總量看。Average Active SessionsAAS陷阱AWR首頁有一個Avg DB Time per Call指標(biāo)但它是平均數(shù)不能反映峰值。一次大批量報表跑批可能平均數(shù)字看起來不高實際運行過程中瞬間并發(fā)會話數(shù)已經(jīng)觸頂。SQL ordered by Gets vs Reads邏輯讀Gets和物理讀Reads排序的SQL往往不是同一批。前者影響CPU后者影響磁盤I/O。優(yōu)化時要明確目標(biāo)是降CPU還是降I/O不然優(yōu)化方向會打架。報告期間重啟數(shù)據(jù)庫的陷阱如果快照窗口內(nèi)發(fā)生過數(shù)據(jù)庫重啟快照數(shù)據(jù)會中斷部分指標(biāo)比如實例啟動以來的累計值會出現(xiàn)跳變。這種報告直接放棄重新生成別硬分析。這些坑不是從文檔里看來的都是我在生產(chǎn)環(huán)境里一個個踩出來的。AWR報告分析能力的提升本質(zhì)上就是看報告→被坑→驗證判斷→再被坑→再驗證的循環(huán)。多分析歷史報告多和實際故障現(xiàn)象對照慢慢就會形成自己的判斷直覺。下一次再有人甩一份報告讓你給結(jié)論你至少知道該從哪里下刀了。本文還有配套的精品資源點擊獲取