必看干貨 | Oracle常見(jiàn)的等待事件說(shuō)明(上)
1. Buffer busy waits
從本質(zhì)上講,這個(gè)等待事件的產(chǎn)生僅說(shuō)明了一個(gè)會(huì)話在等待一個(gè) Buffer(數(shù)據(jù)塊),但是導(dǎo)致這個(gè)現(xiàn)象的原因卻有很多種。常見(jiàn)的兩種是:
-- 當(dāng)一個(gè)會(huì)話視圖修改一個(gè)數(shù)據(jù)塊,但這個(gè)數(shù)據(jù)塊正在被另一個(gè)會(huì)話修改時(shí)。
-- 當(dāng)一個(gè)會(huì)話需要讀取一個(gè)數(shù)據(jù)塊,但這個(gè)數(shù)據(jù)塊正在被另一個(gè)會(huì)話讀取到內(nèi)存中時(shí)。
在新的版本中,第二種情況已經(jīng)被獨(dú)立出來(lái),以 read by other session 取代~
Buffer busy waits 等待事件常見(jiàn)于數(shù)據(jù)庫(kù)中存在的熱快的時(shí)候,當(dāng)多個(gè)用戶頻繁地讀取或者修改同樣的數(shù)據(jù)塊時(shí),這個(gè)等待事件就會(huì)產(chǎn)生。 如果等待的時(shí)間很長(zhǎng),我們?cè)?AWR 或者 statspack 報(bào)告中就可以看到。
這個(gè)等待事件有三個(gè)參數(shù)。 查看有幾個(gè)參數(shù)我們可以用以下 SQL:
- SQL>select name, parameter1, parameter2, parameter3 from v$event_name where name='buffer busy waits';
- NAME PARAMETER1 PARAMETER2 PARAMETER3
- -------------------- ---------- ---------- ----------
- buffer busy waits file# block# class#
2.Buffer latch
內(nèi)存中數(shù)據(jù)塊的存放位置是記錄在一個(gè) hash 列表(cache buffer chains)當(dāng)中的。 當(dāng)一個(gè)會(huì)話需要訪問(wèn)某個(gè)數(shù)據(jù)塊時(shí),它首先要搜索這個(gè) hash 列表,從列表中獲得數(shù)據(jù)塊的地址,然后通過(guò)這個(gè)地址去訪問(wèn)需要的數(shù)據(jù)塊,這個(gè)列表 Oracle 會(huì)使用一個(gè) latch 來(lái)保護(hù)它的完整性。 當(dāng)一個(gè)會(huì)話需要訪問(wèn)這個(gè)列表時(shí),需要獲取一個(gè) Latch,只有這樣,才能保證這個(gè)列表在這個(gè)會(huì)話的瀏覽當(dāng)中不會(huì)發(fā)生變化。
產(chǎn)生 buffer latch 的等待事件的主要原因是:
Buffer chains 太長(zhǎng),導(dǎo)致會(huì)話搜索這個(gè)列表花費(fèi)的時(shí)間太長(zhǎng),使其他的會(huì)話處于等待狀態(tài)。
同樣的數(shù)據(jù)塊被頻繁訪問(wèn),就是我們通常說(shuō)的熱快問(wèn)題。
這個(gè)等待事件有兩個(gè)參數(shù):
Latch addr: 會(huì)話申請(qǐng)的 latch 在 SGA 中的虛擬地址,通過(guò)以下的 SQL 語(yǔ)句可以根據(jù)這個(gè)地址找到它對(duì)應(yīng)的 Latch 名稱(chēng):
select * from v$latch a,v$latchname b where addr=latch addr and a.latch#=b.latch#;
chain#: buffer chains hash 列表中的索引值,當(dāng)這個(gè)參數(shù)的值等于 s 0xfffffff 時(shí),說(shuō)明當(dāng)前的會(huì)話正在等待一個(gè) LRU latch。
3.Control file parallel write
當(dāng)數(shù)據(jù)庫(kù)中有多個(gè)控制文件的拷貝時(shí),Oracle 需要保證信息同步地寫(xiě)到各個(gè)控制文件當(dāng)中,這是一個(gè)并行的物理操作過(guò)程,因?yàn)榉Q(chēng)為控制文件并行寫(xiě),當(dāng)發(fā)生這樣的操作時(shí),就會(huì)產(chǎn)生 control file parallel write 等待事件。
控制文件頻繁寫(xiě)入的原因很多,比如:
-- 日志切換太過(guò)頻繁,導(dǎo)致控制文件信息相應(yīng)地需要頻繁更新。
-- 系統(tǒng) I/O 出現(xiàn)瓶頸,導(dǎo)致所有 I/O 出現(xiàn)等待。
這個(gè)等待事件包含三個(gè)參數(shù):
--Files: Oracle 要寫(xiě)入的控制文件個(gè)數(shù)。
--Blocks: 寫(xiě)入控制文件的數(shù)據(jù)塊數(shù)目。
--Requests:寫(xiě)入控制請(qǐng)求的 I/O 次數(shù)。
4.Control file sequential read
當(dāng)數(shù)據(jù)庫(kù)需要讀取控制文件上的信息時(shí),會(huì)出現(xiàn)這個(gè)等待事件,因?yàn)榭刂莆募男畔⑹琼樞驅(qū)懙?,所以讀取的時(shí)候也是順序的,因此稱(chēng)為控制文件順序讀,它經(jīng)常發(fā)生在以下情況:
-- 備份控制文件
--RAC 環(huán)境下不同實(shí)例之間控制文件的信息共享
-- 讀取控制文件的文件頭信息
-- 讀取控制文件其他信息
這個(gè)等待事件有三個(gè)參數(shù):
--File#:要讀取信息的控制文件的文件號(hào)。
--Block#: 讀取控制文件信息的起始數(shù)據(jù)塊號(hào)。
--Blocks:需要讀取的控制文件數(shù)據(jù)塊數(shù)目。
5.Db file parallel read
這是一個(gè)很容易引起誤導(dǎo)的等待事件,實(shí)際上這個(gè)等待事件和并行操作(比如并行查詢,并行 DML)沒(méi)有關(guān)系。 這個(gè)事件發(fā)生在數(shù)據(jù)庫(kù)恢復(fù)的時(shí)候,當(dāng)有一些數(shù)據(jù)塊需要恢復(fù)的時(shí)候,Oracle 會(huì)以并行的方式把他們從數(shù)據(jù)文件中讀入到內(nèi)存中進(jìn)行恢復(fù)操作。
這個(gè)等待事件包含三個(gè)參數(shù):
--Files: 操作需要讀取的文件個(gè)數(shù)。
--Blocks: 操作需要讀取的數(shù)據(jù)塊個(gè)數(shù)。
--Requests:操作需要執(zhí)行的 I/O 次數(shù)。
6.Db file parallel write
這是一個(gè)后臺(tái)等待事件,它同樣和用戶的并行操作沒(méi)有關(guān)系,它是由后臺(tái)進(jìn)程 DBWR 產(chǎn)生的,當(dāng)后臺(tái)進(jìn)程 DBWR 想磁盤(pán)上寫(xiě)入臟數(shù)據(jù)時(shí),會(huì)發(fā)生這個(gè)等待。DBWR 會(huì)批量地將臟數(shù)據(jù)并行地寫(xiě)入到磁盤(pán)上相應(yīng)的數(shù)據(jù)文件中,在這個(gè)批次作業(yè)完成之前,DBWR 將出現(xiàn)這個(gè)等待事件。 如果僅僅是這一個(gè)等待事件,對(duì)用戶的操作并沒(méi)有太大的影響,當(dāng)伴隨著出現(xiàn) free buffer waits 等待事件時(shí),說(shuō)明此時(shí)內(nèi)存中可用的空間不足,這時(shí)候會(huì)影響到用戶的操作,比如影響到用戶將臟數(shù)據(jù)塊讀入到內(nèi)存中。當(dāng)出現(xiàn) db file parallel write 等待事件時(shí),可以通過(guò)啟用操作系統(tǒng)的異步 I/O 的方式來(lái)緩解這個(gè)等待。 當(dāng)使用異步 I/O 時(shí),DBWR 不在需要一直等到所有數(shù)據(jù)塊全部寫(xiě)入到磁盤(pán)上,它只需要等到這個(gè)數(shù)據(jù)寫(xiě)入到一個(gè)百分比之后,就可以繼續(xù)進(jìn)行后續(xù)的操作。
這個(gè)等待事件有兩個(gè)參數(shù):
--Requests: 操作需要執(zhí)行的 I/O 次數(shù)。
--Timeouts:等待的超時(shí)時(shí)間。
7.Db file scattered read
這個(gè)等待事件在實(shí)際生產(chǎn)庫(kù)中經(jīng)??梢钥吹?,這是一個(gè)用戶操作引起的等待事件,當(dāng)用戶發(fā)出每次 I/O 需要讀取多個(gè)數(shù)據(jù)塊這樣的 SQL 操作時(shí),會(huì)產(chǎn)生這個(gè)等待事件,最常見(jiàn)的兩種情況是全表掃描(FTS: Full Table Scan)和索引快速掃描(IFFS: index fast full scan)。
這個(gè)名稱(chēng)中的 scattered(發(fā)散),可能會(huì)導(dǎo)致很多人認(rèn)為它是以 scattered 的方式來(lái)讀取數(shù)據(jù)塊的,其實(shí)恰恰相反,當(dāng)發(fā)生這種等待事件時(shí),SQL 的操作都是順序地讀取數(shù)據(jù)塊的,比如 FTS 或者 IFFS 方式(如果忽略需要讀取的數(shù)據(jù)塊已經(jīng)存在內(nèi)存中的情況)。這里的 scattered 指的是讀取的數(shù)據(jù)塊在內(nèi)存中的存放方式,他們被讀取到內(nèi)存中后,是以分散的方式存在在內(nèi)存中,而不是連續(xù)的。
這個(gè)等待事件有三個(gè)參數(shù):
--File#: 要讀取的數(shù)據(jù)塊所在數(shù)據(jù)文件的文件號(hào)。
--Block#: 要讀取的起始數(shù)據(jù)塊號(hào)。
--Blocks:需要讀取的數(shù)據(jù)塊數(shù)目。
8.Db file sequential read
這個(gè)等待事件在實(shí)際生產(chǎn)庫(kù)也很常見(jiàn),當(dāng) Oracle 需要每次 I/O 只讀取單個(gè)數(shù)據(jù)塊這樣的操作時(shí),會(huì)產(chǎn)生這個(gè)等待事件。 最常見(jiàn)的情況有索引的訪問(wèn)(除 IFFS 外的方式),回滾操作,以 ROWID 的方式訪問(wèn)表中的數(shù)據(jù),重建控制文件,對(duì)文件頭做 DUMP 等。這里的 sequential 也并非指的是 Oracle 按順序的方式來(lái)訪問(wèn)數(shù)據(jù),和 db file scattered read 一樣,它指的是讀取的數(shù)據(jù)塊在內(nèi)存中是以連續(xù)的方式存放的。
這個(gè)等待事件有三個(gè)參數(shù):
--File#: 要讀取的數(shù)據(jù)塊鎖在數(shù)據(jù)文件的文件號(hào)。
--Block#: 要讀取的起始數(shù)據(jù)塊號(hào)。
--Blocks:要讀取的數(shù)據(jù)塊數(shù)目(這里應(yīng)該等于 1)。
9.Db file single write
這個(gè)等待事件通常只發(fā)生在一種情況下,就是 Oracle 更新數(shù)據(jù)文件頭信息時(shí)(比如發(fā)生 Checkpoint)。當(dāng)這個(gè)等待事件很明顯時(shí),需要考慮是不是數(shù)據(jù)庫(kù)中的數(shù)據(jù)文件數(shù)量太大,導(dǎo)致 Oracle 需要花較長(zhǎng)的時(shí)間來(lái)做所有文件頭的更新操作(checkpoint)。
這個(gè)等待事件有三個(gè)參數(shù):
--File#: 需要更新的數(shù)據(jù)塊所在的數(shù)據(jù)文件的文件號(hào)。
--Block#:需要更新的數(shù)據(jù)塊號(hào)。
--Blocks:需要更新的數(shù)據(jù)塊數(shù)目(通常來(lái)說(shuō)應(yīng)該等于 1)。
10.Direct path read
這個(gè)等待事件發(fā)生在會(huì)話將數(shù)據(jù)塊直接讀取到 PGA 當(dāng)中而不是 SGA 中的情況,這些被讀取的數(shù)據(jù)通常是這個(gè)會(huì)話私有的數(shù)據(jù),所以不需要放到 SGA 作為共享數(shù)據(jù),因?yàn)檫@樣做沒(méi)有意義。 這些數(shù)據(jù)通常是來(lái)自與臨時(shí)段上的數(shù)據(jù),比如一個(gè)會(huì)話中 SQL 的排序數(shù)據(jù),并行執(zhí)行過(guò)程中間產(chǎn)生的數(shù)據(jù),以及 Hash Join,merge join 產(chǎn)生的排序數(shù)據(jù),因?yàn)檫@些數(shù)據(jù)只對(duì)當(dāng)前的會(huì)話的 SQL 操作有意義,所以不需要放到 SGA 當(dāng)中。當(dāng)發(fā)生 direct path read 等待事件時(shí),意味著磁盤(pán)上有大量的臨時(shí)數(shù)據(jù)產(chǎn)生,比如排序,并行執(zhí)行等操作。 或者意味著 PGA 中空閑空間不足。
這個(gè)等待事件有三個(gè)參數(shù):
--Descriptor address: 一個(gè)指針,指向當(dāng)前會(huì)話正在等待的一個(gè) direct read I/O。
--First dba: descriptor address 中最舊的一個(gè) I/O 數(shù)據(jù)塊地址。
--Block cnt: descriptor address 上下文中涉及的有效的 buffer 數(shù)量。
11.Direct path write
這個(gè)等待事件和 direct path read 正好相反,是會(huì)話將一些數(shù)據(jù)從 PGA 中直接寫(xiě)入到磁盤(pán)文件上,而不經(jīng)過(guò) SGA。
這種情況通常發(fā)生在:
-- 使用臨時(shí)表空間排序(內(nèi)存不足)
-- 數(shù)據(jù)的直接加載(使用 append 方式加載數(shù)據(jù))
-- 并行 DML 操作。
這個(gè)等待事件有三個(gè)參數(shù):
--Descriptor address: 一個(gè)指針,指向當(dāng)前會(huì)話正在等待的一個(gè) direct I/O.
--First dba: descriptor address 中最舊的一個(gè) I/O 數(shù)據(jù)塊地址。
--Block cnt: descriptor address 上下文中涉及的有效地 buffer 數(shù)量。
12.Enqueue
Enqueue 這個(gè)詞其實(shí)是 lock 的另一種描述語(yǔ)。當(dāng)我們?cè)?AWR 報(bào)告中發(fā)現(xiàn)長(zhǎng)時(shí)間的 enqueue 等待事件時(shí),說(shuō)明數(shù)據(jù)庫(kù)中出現(xiàn)了阻塞和等待,可以關(guān)聯(lián) AWR 報(bào)告中的 enqueue activity 部分來(lái)確定是哪一種鎖定出現(xiàn)了長(zhǎng)時(shí)間等待。
這個(gè)等待事件有 2 個(gè)參數(shù):
--Name: enqueue 的名稱(chēng)和類(lèi)型。
--Mode: enqueue 的模式。
13.Free buffer waits
當(dāng)一個(gè)會(huì)話將數(shù)據(jù)塊從磁盤(pán)讀到內(nèi)存中時(shí),它需要到內(nèi)存中找到空閑的內(nèi)存空間來(lái)存放這些數(shù)據(jù)塊,當(dāng)內(nèi)存中沒(méi)有空閑的空間時(shí),就會(huì)產(chǎn)生這個(gè)等待;除此之外,還有一種情況就是會(huì)話在做一致性讀時(shí),需要構(gòu)造數(shù)據(jù)塊在某個(gè)時(shí)刻的前映像(image),此時(shí)需要申請(qǐng)內(nèi)存來(lái)存放這些新構(gòu)造的數(shù)據(jù)塊,如果內(nèi)存中無(wú)法找到這樣的內(nèi)存塊,也會(huì)發(fā)生這個(gè)等待事件。
當(dāng)數(shù)據(jù)庫(kù)中出現(xiàn)比較嚴(yán)重的 free buffer waits 等待事件時(shí),可能的原因是:
--data buffer 太小,導(dǎo)致空閑空間不夠
-- 內(nèi)存中的臟數(shù)據(jù)太多,DBWR 無(wú)法及時(shí)將這些臟數(shù)據(jù)寫(xiě)到磁盤(pán)中以釋放空間
這個(gè)等待事件包含 2 個(gè)參數(shù):
--File#: 需要讀取的數(shù)據(jù)塊所在的數(shù)據(jù)文件的文件號(hào)。
--Block#: 需要讀取的數(shù)據(jù)塊塊號(hào)。
-- 查詢阻塞的語(yǔ)句:
- SELECT /*+ ORDERED USE_HASH(H,R) */
- h.sid hold_sid, holds.username h_user, holds.lockwait h_lockwait, holds.status h_status, holds.module h_module, holds.row_wait_obj# h_obj, holds.row_wait_row# h_row,
- r.sid wait_sid, waits.username w_user, waits.lockwait w_lockwait, waits.status w_status, waits.module w_module, waits.row_wait_obj# w_obj, waits.row_wait_row# w_row,
- h.type h_type, h.id1 h_id1, h.id2 h_id2, h.lmode h_lmode, h.request h_request, h.ctime h_ctime, h.block h_block, r.type r_type, r.id1 r_id1, r.id2 r_id2, r.lmode r_lmode,
- r.request r_request, r.ctime r_ctime, r.block r_block,'alter system kill session'''|| holds.sid ||','|| holds.serial# ||'''; -- kill -9'|| nvl(holdp.spid,'null') killhold,
- holdsql.sql_text hsql, waitsql.sql_text wsql
- FROM v$lock h,
- v$lock r,
- v$session holds,
- v$session waits,
- v$process holdp,
- v$sqlarea holdsql,
- v$sqlarea waitsql
- WHERE h.BLOCK =1 AND r.BLOCK=0 AND h.TYPE <>'MR' AND r.TYPE <>'MR' AND h.id1 = r.id1 AND h.id2 = r.id2 AND h.sid = holds.sid AND r.sid = waits.sid AND holds.paddr = holdp.addr(+)
- AND holds.sql_address = holdsql.address(+) AND holds.sql_hash_value = holdsql.hash_value(+) AND waits.sql_address = waitsql.address(+) AND waits.sql_hash_value = waitsql.hash_value(+);
14.Latch free
在 10g 之前的版本里,latch free 等待事件代表了所有的 latch 等待,在 10g 以后,一些常用的 latch 事件已經(jīng)被獨(dú)立了出來(lái):
這個(gè)等待事件有三個(gè)參數(shù):
--Address: 會(huì)話等待的 latch 地址。
--Number: latch 號(hào),通過(guò)這個(gè)號(hào),可以從 v$latchname 視圖中找到這個(gè) latch 的相關(guān)的信息。
15.Library cache lock
這個(gè)等待時(shí)間發(fā)生在不同用戶在共享中由于并發(fā)操作同一個(gè)數(shù)據(jù)庫(kù)對(duì)象導(dǎo)致的資源爭(zhēng)用的時(shí)候,比如當(dāng)一個(gè)用戶正在對(duì)一個(gè)表做 DDL 操作時(shí),其他的用戶如果要訪問(wèn)這張表,就會(huì)發(fā)生 library cache lock 等待事件,它要一直等到 DDL 操作完成后,才能繼續(xù)操作。
這個(gè)事件包含四個(gè)參數(shù):
--Handle address: 被加載的對(duì)象的地址。
--Lock address: 鎖的地址。
--Mode: 被加載對(duì)象的數(shù)據(jù)片段。
--Namespace: 被加載對(duì)象在 v$db_object_cache 視圖中 namespace 名稱(chēng)。























