Steve Adams的《Oracle8i internal services for waits, latches, locks》試譯

tom165發表於2011-09-02

以前學習Oracle時,看到一些高手都推薦Steve Adams的《Oracle8i Internal Services for Waits, Latches, Locks》一書, 說對ORACLE的底層的鎖等有深入的描述。學習的時候試譯了幾章,現貼下,供大家參考。

基於Oracle 8i的8.1版,這本簡潔的書包含了關於Oracle的內部詳細的隱藏資訊(資料結構、演算法、隱藏引數、未公開的系統統計),書的大部分主題包括了等待、閘、鎖(包括用於並行服務環境的例項鎖)、記憶體使用和管理,它的目標讀者是做相關高階效能調優的。

目錄

前言

為什麼寫這本書

警告

宣告

關於APT指令碼

本書慣例

註解和問題

感謝

  1. 緒論

1.1 oracle核心層

1.2 核心服務

  1. 等待

2.1 訊號量

2.2 等待統計

2.3 參考資料

3.1 閂和鎖

3.2 父閂和子閂

3.3 閂獲得

3.4 高階閂控制

4.1 鎖的狀態

4.2 鎖的模式

4.3 佇列鎖

4.4 行cache佇列

4.5 庫cache鎖和Pins

4.6 DML鎖

4.7 快取鎖

4.8 排序鎖

4.9 參考

  1. 例項鎖

5.1 鎖管理器

5.2 全域性鎖

5.3 PCM例項鎖

5.4 其他例項鎖

5.5 參考

  1. 內容

6.1 SGA

6.2 共享池

6.3 程式記憶體

6.4 參考

1.緒論

為何人們對Oracle內部資訊有強烈的興趣?部分是因為內部資訊對效能調優和排錯很有用,並且由於Oracle公司保留了大部分核心資訊,使得更有引誘力。

實際上,只有高階的效能調優才需要Oracle內部資訊,最需要的、絕大多數的效能調優都是基本的應用調優。儘管如此,有時高階的效能調優是必需的,那時你需要深入理解Oracle是如何運作的。這本書提供了這方面的基礎知識。

為了欣賞這本書的內容,理解相關內容,你需要對Oracle的核心層次有個基本瞭解。

1.1 Oracle核心層次

Oracle核心由多個層次組成,主要的層次顯示在圖1.1中。每一層依賴它下面層次的服務,並且可以任意的直接呼叫它們。然而,除非從呼叫中返回,控制從不經過堆疊。

一個明顯的例外是資料層和交易層有時需要執行遞迴任務,如索引塊分裂或外部空間管理,在儲存程式單元裡執行觸發器或SQL語句也需要遞迴呼叫。但它並不是在同一個回話或呼叫上下文環境中反向呼叫核心執行或編譯層,而是建立一個單獨的上下文環境,堆疊從頂層重進入。

每一層都有一個別名或簡寫,通常是它的模組的名字。例如,KC是核心快取層(kernel cache )的別名。這些別名顯示在圖1.1和下面的列表中。類似的,構成層的每個模組也有一個別名。例如,KCR是快取層的redo管理模組。

這些模組名字是模組的資料結構和功能呼叫的命名字首。例如,KCRFAL是redo分配閂。這種命名慣例使Oracle中的名字初看起來相當隱祕和令人畏懼,但不久就變得令人驚奇的容易識別,並極大的幫助我們去理解。儘管如此,你將高興地知道本書更喜歡用全名而不是有點隱祕的替換詞。

Oracle呼叫介面(OCI)

Oracle呼叫介面是客戶端程式和Oracle互動作用的最底層。這個介面的文件豐富,並提供了對Oracle的大多數功能的呼叫,包括物件導向、複雜 交易、會話控制等高階特性。為了利用其他Oracle開發工具不提供的特性,一些有高階需求的應用程式需要直接使用OCI介面。

使用者程式介面(UPI)

OCI是建立在使用者程式介面上的。有一些UPI的特性是OCI中沒有的,並且一些Oracle工具實際上直接呼叫了這個介面,預編譯程式也間接的通過SQLLIB(是未公開的OCI替換介面)呼叫UPI。

Oracle程式設計介面(OPI)

使用者程式介面是客戶端呼叫堆疊的最底層,Oracle程式設計介面是伺服器端呼叫堆疊的最頂層。在大多數配置中,Net8在UPI和OPI中起了橋樑作用,但在單任務執行條件下,UPI呼叫直接對應OPI呼叫。

編譯層(KK)

這是Oracle核心的嚴格意義上的頂層,它負責解析優化SQL語句,編譯PL/SQL程式單元。

執行層(KX)

這層處理SQL語句和PL/SQL程式單元的繫結和執行,還負責執行觸發器的遞迴呼叫執行,以及SQL語句在PL/SQL單元內的執行。

分佈執行層(K2)

分佈執行層建立分散式事務的事務分支,管理兩階段提交協議。

網路程式設計介面(NPI)

SQL語句引用遠端物件時,NPI給遠端資料庫例項傳遞分解後的語句成分,並接受返回的資料。

安全層(KZ)

編譯層和執行層呼叫安全層,驗證被請求物件和系統的許可權。

查詢層(KQ)

查詢層對更高的層提供記錄,特別地,查詢層負責用於安全層和編譯層的資料字典的緩衝記錄。

遞迴程式介面(RPI)

遞迴程式設計介面用於填充資料字典的字典緩衝。行緩衝遞迴SQL語句在分離的呼叫上下文中執行,不在編譯層中解析優化。

存取層(KA)

存取層負責存取資料庫段。這是核心的第一個底層部分。

資料層(KD)

資料層負責對資料庫段的塊中的資料(如表、簇、索引)進行解釋。

事務層(KT)

事務層負責回滾段中的事務分配,記錄資料塊中的事務清單變化,為了undo的操作、事務控制中的儲存點等屬性、讀一致等功能改變回滾段塊。事務層也在段自由列表和表空間擴充套件分配級別上負責空間管理。

緩衝層(KC)

緩衝層管理資料庫的快取。它利用作業系統的資料檔案I/O特性,為本地快取的讀取提供併發控制,為Oracle並行伺服器提供並行快取管理(PCM)例項的鎖定特性。緩衝層的其他主要任務是控制redo資料進入日誌快取,並寫入日誌檔案。緩衝層還快取控制檔案資訊。

服務層(KS)

服務層提供的底層服務被用於如錯誤處理、除錯、跟蹤、引數控制、記憶體服務等更高層。特別地,服務層負責如閂 、事件等待、佇列鎖、例項鎖等通用併發控制,也對如物件狀態、程式間訊息、系統統計等後臺資料結構和使用者程式和會話進行管理。

鎖管理層(KJ)

鎖管理層負責並行服務資料庫例項的鎖的同步和通訊。

通用層(KG)

通用層負責對用於更高層的如連結清單等通用資料結構進行管理,尤其是用於共享池和會話的庫緩衝和內從分配堆。

作業系統依賴層(S)

Oracle使用了一些作業系統功能,如I/O,程式排程,記憶體管理和其他功能。這些功能的實現細節依賴於作業系統的,所以把這些功能脫離出來分成一個單獨層。

1.2 核心服務

本書包含了等待事件、閂 、鎖、記憶體等核心服務。雖然你很少能對這些服務進行調優,但你對Oracle的其他方面進行調優就需要理解這些服務。

第二章:等待事件統計是oracle高階效能調優中最重要的統計項。本章介紹瞭如何收集和使用這些統計項。

第三章:Oracle中大量使用閂 ,高階效能調優經常要防止閂競爭。本章通過講解如何使用閂,對這類調優建立了基礎。

第四章:Oracle使用了很多型別的鎖。本章講解如何使用鎖,如何診斷鎖的問題。

第五章:Oracle並行服務技術擴充套件了Oracle調優的規模。本章講解了並行服務鎖是如何執行的,統計項意味著什麼。

第六章:本章講解了Oracle的內部記憶體管理是如何工作的。特別注意共享池的內部工作機理,以及核定是否大小正確。

儘管這部小書涵蓋了Oracle的很多內部資訊,但這些章節的內容只是為你進行高階效能調優提供了一個基礎。

第二章: 等待事件

在一個Oracle例項中許多程式或執行緒(單程式中)一起執行。為了一起執行,他們之間要互相通訊,一個主要的通訊手段是訊號量。一個訊號量就是一種訊號。有點像鐵路訊號,告訴列車是停止還是等待,何時開。Oracle伺服器程式經常需要停止和等待:

-有時因為資源不可等到 -有時因為沒有任務 -有時因為需要等待其他伺服器程式完成預先任務 -訊號量能讓Oracle伺服器程式停止和等待,並通知他們何時重新開始處理

2.1 訊號量

每一個Oracle伺服器程式都有一個訊號量。程式在需要等待資源、需要去做某一任務、需要某一任務完成時都等待訊號量。當資源釋放、任務可以去做、預先任務已完成時,停止等待的訊號量就釋出了。

例如,在一個使用者程式把redo資訊寫進redo日誌快取時,寫日誌寫程式(LGWR)可能等待工作的訊號量。當使用者提交時,LGWR必須寫入redo, 並且在使用者等待時提交日誌檔案的標記。為了完成這些工作,使用者程式釋出LGWR的訊號量,表明LGWR可以停止等待,有工作需要做了,然後使用者程式等待它 自身的訊號量。當日志檔案的讀寫工作完成後,LGWR釋出使用者程式的訊號量表明提交操作完成,它能進行下一事務了。LGWR因為無事可做又等待它的訊號量 了。

另一個例子是,程式A要更新一行記錄,但發現程式B對同一行記錄的更新還沒提交。程式A必須等待程式B提交。為了完成更新,程式A將等待訊號量,當程式B提交時,它將釋出程式A的訊號量,表明可以進行更新操作了。

2.1.1 訊號量特性

訊號量是一個作業系統的特性。當一個Oracle程式等待訊號量時,作業系統不會排程它去執行。在作業系統看來,它被阻塞了,不可執行。當訊號量釋出,進 程的作業系統狀態從阻塞變為可執行,將被儘快的排程執行。一些作業系統支援多種訊號量。SYSTEM V的訊號量是最常見的。SYSTEM V的訊號量的資料結構由一個核心記憶體中的固定陣列組成,它的大小由SEMMNS核心引數控制。程式必須用semop()系統呼叫釋出或等待訊號量。由於它們是在作業系統的核心實現的,SYSTEMV的訊號量在高層系統呼叫時不得不進行上下文切換,並由於讀取核心資料結構的序列化需要而擴充套件性較差。

為了更好的效能和擴充套件性,有的作業系統也提供其他方法用於替換訊號量。在一個偽裝置驅動中實現了釋出等待驅動事件。這些訊號量的資料結構駐留在使用者記憶體, 而不是核心記憶體;通過偽裝置驅動,能在使用者上下文環境中操作。減少了系統呼叫的上下文切換,提高了擴充套件性。但它是和特定的作業系統相關的。

POSIX實時擴充套件小型委員會曾經確定了一個使用者記憶體中的訊號量特性的編輯標準需求。POSIX.1b標準(早期的POSIX.4)為這個訊號量特性定義了介面和實現需求,不考慮移植性的話,它是簡潔高效的。

Oracle使用的訊號量特性是與作業系統和版本相關的。如果你的Oracle安裝指南中有設定SEMMNS核心引數的指令,意味著預設使用的是System V的訊號量。不幸的是這是大多數作業系統所採用的。順便提一下,不考慮工程中的Oracle程式數或其他系統和應用軟體,普遍推薦設定SEMMNS為200是被誤導的。你必須讓一個Oracle伺服器程式有一個訊號量,對於其他附加需求,在表2.1中有更多說明。

你也應意識到在一些平臺上,oracle例項需要它的訊號量被分配再一個單一的訊號量集合裡。所以SEMMNI引數對每個例項僅僅允許一個訊號量標識 符,SEMMSL引數(如果定義過的話)對任何例項來說必須不小於PROCESSES引數的最大值。這對vector posts是必須的。主要關鍵程式LGWR和DBWIN用vector posts來在單個訊號量操作中提交多個等待程式。vector posts的使用依賴於_USE_VECTOR_POSTS引數的設定。

————————————————————————————————————————————————

隱藏引數

像_USE_VECTOR_POSTS一樣,以底劃線開始的引數是隱藏引數。因為是隱藏的,在V$PARAMETER中找不到他們,但可以用SHOW PATAMETERS命令檢視。因為是未公開的,在oracle文件中也找不到它們的說明。然而,你可以用APT指令碼 hidden_parameters.sql得到它們的解釋,用指令碼all_parameters.sql檢查它們的值。有些隱藏引數是作業系統相關的。 有些只在異常回復情況下需要。有些用於開啟會關閉新的功能。很多與不重要的效能問題相關。如所有的未公開特性一樣,隱藏引數在將來的版本中可能消失或改變,因此,你應該把它們作為一種終極手段,要用在oracle的技術支援檢查後,併為你的繼任完整的寫下問題文件。

————————————————————————————————————————————————

此外,如果你的作業系統定義了SEMMNU核心引數,它應當比作業系統層面的併發訊號量工程數大。對於有許多訊號量客戶程式的系統,預設值是不夠的。如果這樣的話,訊號量操作在峰值活躍期間將斷斷續續地失敗並返回ORA-7264或ORA-7265錯誤。為了避免這種情況,SEMMNU引數必須至少與CPU數和峰值時的CPU執行佇列之和相等。

————————————————————————————————————————————————

表2.1 System V訊號量引數

引數 解釋

SEMMNS :

系統中的訊號量數。除滿足作業系統和其他軟體的需求外,你應當要求每個Oracle服務程式至少有一個訊號量,更確切的說,是系統中所有例項的 PROCESSES引數的值的和。如果訊號量客戶端不是一直嚴格按關閉、啟動的順序操作的話,推薦至少加上 等於單個需求的額外補助。另外,由核心引數控制的單個使用者同時擁有的最大程式數(一般稱作MAXUP),應不小於SEMMNS的值,額外的,Oracle使用者的其他管理程式不需要訊號量。然而,這個值不應該大到有讓其他使用者製造太多程式以致核心程式表被完全填滿的風險。因此,由核心引數控制的所有使用者的同 時最大程式數(一般稱作NPROC)應該至少是SEMMNS引數值的三倍。

SEMMSL:

單個訊號量集合的大小限制值。有些作業系統未定義這個引數。一旦它定義了,Oracle就要求一個例項的所有訊號量分配在也個單獨訊號量集合中。這個引數必須不小於任意例項要求的PROCESSES引數的最到值。

SEMMNI:

系統中的訊號量集合的識別符號數。除滿足作業系統和其他軟體的需求外,你應當允許每個例項有一個識別符號,如果SEMMSL引數設定了多個訊號量集合,任何例項可以要求多個識別符號。

SEMMNU:

系統中的訊號量undo結構數。在訊號量操作的異常程式關閉事件中,undo結構用於恢復核心訊號量資料結構。SEMMNU值應當大於峰值時的執行和可執行的程式數。

————————————————————————————————————————————————

如果你的作業系統中Oracle預設使用system V訊號量,同時也支援使用post-wait driver,應該選擇使用post-wait driver。這通常要把USE_POST_WAIT_DRIVER引數設為TRUE,有時還必須設定POST_WAIT_DEVICE引數。因為與操作 系統和版本相關,請查閱Oracle安裝指南。

如果你的安裝指南沒有涉及核心訊號量引數設定和post-wait driver,那你的作業系統的訊號量功能的選擇和配置是自動的。

注:訊號量引數是作業系統核心引數,不能在oracle初始化引數檔案INIT.ORA中設定。

2.1.2 排程潛伏期

當一個程式提交後,它的作業系統狀態從阻塞變為可執行。然而,這並不意味著它將立即被排程在CPU上執行。它必須至少等待作業系統的進行排程器的下一次執行,如果有更高優先順序的程式在等待執行,那還要等待更久。一個程式從提交到開始執行的間隔時間就是排程潛伏期。排程潛伏期對oracle的響應時間的影響,在圖2.1中有解釋,效能調優的一個重要部分是縮短排程潛伏期。

許多作業系統的排程演算法會調整程式的執行優先順序,使之與他們最近使用CPU的時間大小成比例。不幸的是,在很繁忙的oracle環境中,這會降低如 LGWR,DBWn,LCKn,LMDn等關鍵後臺程式的執行優先順序。會使這些程式的排程潛伏期增加,在極端情況下,會形成這些被影響的後臺程式服務的全部例項的瓶頸。

有的作業系統支援多種排程演算法。有可能的話,你應該選擇不會象上面講的一樣降低程式執行優先順序的排程演算法。為了彌補這個缺點,你的作業系統可能提供了一種優先順序固定的特性。如果程式的執行優先順序被固定了,就不會被降低了。在一些情況下,所有使用者都可使用優先順序固定,Oracle會自動使用它。在其他情況下,只有系統管理員和特別授權使用者可使用優先順序固定,Oracle使用者必須被授權才可使用優先順序固定,或者用系統管理員用一個固定優先順序的命令列指令碼啟動Oracle例項,這樣所有的Oracle程式就用固定優先順序執行了。

當優先順序固定不可用時,從優先順序的降低原理考慮,為獲得相同的效果,你可以人工調高關鍵後臺程式的執行優先順序和,或用實時程式優先順序來執行。由於Oracle經常推薦所有Oracle程式用相同的優先順序執行,你可能不願這麼做。這個推薦方法是為了防止由於低優先順序的程式佔用了關鍵資源但由於沒有CPU使用時間而無法釋放,而其他高優先順序程式試圖重複獲得該資源。但調高關鍵後臺程式的執行優先順序極少發生這種情況。如果這些程式要求的資源得不到,它們不久將變為休眠狀態,除此以外,只使用與其他例項的工作數量所成比例的CPU時間。所以它們對其他Oracle程式沒有CPU空閒風險。

2.1.3 超時

Oracle服務程式從不願無限期地等待,免得永遠被提交和等待。幸運的是,訊號量等待可以被中斷。所以在Oracle程式開始等待訊號量前,他通過設定一個警告定時,也叫超時時間來中斷他的休眠期。如果程式提交了,警告定時會關掉並繼續執行;如果定時被超時,等待就通過一個SIGALRM訊號被中斷。程式又有機會重新評估狀況,並決定是否繼續等待。

例如,一個程式在等待佇列鎖,當定時被超時,會檢測是否死鎖。如果有死鎖,會回滾並引起一個異常,如果沒有死鎖,程式會設定一個新的定時並重新開始等待訊號量。

有時會發生程式定時太短,以致於關閉定時的警告都來不及釋出。對這種情況,Oracle程式會在跟蹤檔案中寫入一條訊息:Ignoring SIGALRM,如果你發現以上資訊的跟蹤檔案,這沒有任何告警。它僅僅告訴你等待程式提交速度並不像你想像的一樣快。你應該從等待時間統計中找到一些問題。

第三章 閂

ORACLE系統全域性區(SGA)裡有無數資料結構,許多不同的資料庫程式需要對它們進行併發讀寫。任何資料結構在某一時刻只能被一個程式修改,並且在被檢視時是不能被修改的。Oracle通過鎖或閂來保護SGA中的資料結構來確保這種情況不會發生。

3.1 閂和鎖

閂理論上比鎖更受限制,因為閂只提供排他性的讀取,不允許多個程式同時檢視被保護的資料結構(注1),而鎖有更好的併發性,允許資料結構在共享模式下簡單的檢視。

注1:這是簡化的說法,redo複製閂能在基於硬體的條件下被共享。

閂和鎖的另一個有意思的區別是在請求佇列上。如果需要鎖的請求是按佇列排序服務的,但閂不支援請求佇列。加入一個閂的請求由於閂太忙而失敗,程式將繼續重試直到成功,所以閂不必排序服務。

由於閂在某個時刻只能被一個程式持有,且沒有佇列的概念,閂本身的資料結構是非常簡單的——本質上只是一個記憶體中的儲存單元,用於表示閂的狀態。由於閂的 資料結構如此簡單,閂的獲得和釋放都是非常輕鬆的。相反,由於鎖支援佇列和併發,鎖的資料結構複雜得多,鎖在獲得、轉換、釋放上要做更多的工作。

對於Oracle來說,同一時刻保證只有一個程式能修改自己的閂和鎖的資料結構是理所當然的。對閂而言這很簡單,因為每個閂只是記憶體中的一個儲存單元,Oracle能用基本的硬體指令(如TEST和SET,LOAD和CLEAR,COMPARE和SWAP指令)對閂進行操作。由於不需要其他鎖保護機制,這些簡單的指令能保證操作是原子級的。這種簡單性使閂的效率非常高。

另一方面,Oracle的鎖結構有好幾部分,不能在原子操作級別上修改。所以,Oracle實際上用閂來保護鎖的操作。不同型別的閂用來保護不用型別的 鎖。例如,快取鎖簡介的被快取鏈閂保護,行快取佇列鎖被行快取物件閂保護。由於閂比鎖更有效,在短時和間歇讀取資料時,Oracle經常用閂來保護資料,而不是鎖和聯合閂。

3.2 父閂和子閂

大部分用閂保護的Oracle內部資料結構只用一個閂來保護。但有時也用多個閂來保護。例如,有許多庫快取閂用來來保護庫快取中的不同組物件,不同的快取鏈閂用來保護資料庫的每個快取雜湊鏈。

每當許多閂用來保護不同的結構部分或相同結構,這些閂叫子閂。每一相同型別的子閂集合有一個父閂。一般來說,父閂和子閂同時使用。但實際上,在父閂中你只願意使用庫快取父閂,儘管如此,與它的子閂的活躍性相比,父閂極少發生。

有點令人困惑的是,Oracle總把沒有後代的單獨的閂叫做父閂。每個單獨的閂在V$LATCH_PARENT檢視中都有一行記錄,每個真正的父閂也有一行記錄。每個子閂在V$LATCH_CHILDREN中有一行記錄,兩個檢視的結合包括了所有的閂。

不管是單獨的閂或父閂和子閂的集合,Oracle使用的閂的型別隨Oracle版本和作業系統埠的不同而變化。APT指令碼 latch_types.sql能用來檢視你的資料庫使用的閂的型別,如果是父閂和子閂的集合,還顯示出有多少子閂。例3.1顯示了該指令碼的一個輸出摘要:

例3.1 latch_types.sql輸出樣式:

SQL> @latch_types
—— —————————— —— ——-
0 latch wait list                     1       1
1 process allocation                  1
2 session allocation                  1
3 session switching                   1
4 session idle bit                    1       1
…

APT指令碼和X$表

書中的許多APT指令碼,如latch_types.sql, 直接使用X$表,而不是V$檢視。這是因為V$檢視不包含要求的資訊,或因為查詢V$檢視會引起例項的不好的負荷。因為X$表只在SYS模式下可以檢視,而且不必要的用SYS模式來工作是不好的,所以APT要求你給其他DBA模式建立暴露X$表的檢視集合。這可以用 create_xview.sql指令碼完成,它必須執行在SYS模式下。沒有這些檢視,所有的依賴X$表的APT指令碼都會失效。

要注意X$表隨資料庫的版本變化而變化,所以APT指令碼是與版本相關的,確保按你的Oracle版本使用正確的指令碼。

V$LATCH檢視包含了按閂型別分組的統計彙總。當調查一個閂問題時,V$LATCH應當是你的參考起點。如果問題與相同型別的閂的集合相關,你應當用V$LACTH_CHILDREN檢視在子閂中的活躍分佈,用V$LACTH_PARENT來判斷相對於父閂的活躍性。

3.3 閂的獲得

當Oracle程式需要讀寫被閂保護的資料結構時,有兩種模式去要求獲得閂,分別是願意等待模式或不等待模式(也叫立即模式)。

3.3.1 願意等待模式

oracle期待閂被斷時間歇的持有,所以如果一個程式試圖通過願意等待模式獲得閂,並發現閂得不到,將短時自旋並重試。程式自旋時,作為等待方式,在重試前多次執行一系列簡單指令。雖然是在真正的等待,從作業系統的角度看還在使用CPU週期,所以有時又叫做活躍等待。

在重試獲得閂之前,程式佔用的CPU時間數是很小的,固定的(但在Oracle7裡可以用_LATCH_SPIN_COUNT引數調節)。如果下一次沒有獲得閂,這個過程將重複,直到達到_SPIN_COUNT引數指定的次數。在多處理器環境下這個引數通常預設是2000次。

3.3.1.1 為何自旋?

自旋的概念是在其他CPU上執行的其他程式可能會釋放出閂來,因而允許自旋程式繼續執行。當然,在單CPU機器上自旋是沒有意義的,Oracle也不會那樣做。

自旋的替換是讓出CPU,允許其他程式使用。初看起來這是個好主意。然而,要一個CPU停止一個程式並開始執行其他程式,它必須進行上下文切換。就是說, 它必須儲存第一個程式的上下文,確定接下來排程的程式,恢復下個程式的上下文。一個程式的上下文字質上就是描述程式精確狀態的CPU暫存器值的一個集合。

上下文切換的實現是高度依賴機器的。實際上,它是典型的用匯編語言編寫的。系統提供商用盡所有辦法來減少上下文的資料大小,用各種方法來優化上下文切換, 如用重影射記憶體地址而不是拷貝資料。儘管如此,由於要對許多核心資料結構進行查詢和更新,上下文切換仍然是一種昂貴的操作。讀取這些資料結構是用自旋保護 的,相當於作業系統的閂。在一個大而繁忙的系統中,上下文切換通常消耗1%到3%的CPU時間。所以如果能用短時的自旋來替換上下文切換,有些CPU時間 就會節約下來,獲得閂的等待時間會被最小化。從這個原因來說,系統更傾向於短時自旋而不是立即讓出CPU。

3.3.1.2 理解自旋統計值

V$LACTH類的檢視中的閂統計值記錄了程式在願意等待模式下獲得閂的次數。如果程式沒有自旋沒有獲得閂,一個閂缺失會被記錄。如果閂在一個或多個自旋重複後被獲得,一個閂獲得會被記錄。如果自旋時閂不能獲得,程式會讓出CPU並進入睡眠。不管程式後來喚醒,自旋,又睡眠多少次,不管將來記錄的是閂的獲得還是缺失,如果閂最終通過自旋獲得,只有一個閂獲得被記錄。所以,沒有自旋獲得閂的次數根本是缺失次數。我叫做簡單獲得次數APT指令碼latch_gets.sql顯示了按簡單獲得次數、自旋獲得次數,睡眠獲得次數(睡眠獲得的)的閂獲得統計分析。例3.2顯示了一些輸出樣式。

例3.2 latch_gets.sql指令碼輸出樣式:

SQL> @latch_gets
—————————— —————— ————– ————–
 archive control                       228 100.00%       0  0.00%   0  0.00%
cache buffer handles                67399 100.00%       0  0.00% 0  0.00%
cache buffers chains           2948282897 100.00%   11811  0.00%   35999  0.00%
cache buffers lru chain          56863812  99.60%   44364  0.08%  182480  0.32%
dml lock allocation               2047579  99.99%      36  0.00%     199  0.01%
enqueue hash chains              14960087  99.95%    1139  0.01% 6603  0.04%
enqueues                         24759299 100.00%     165  0.00%     861  0.00%
…

也許更有趣的是,APT指令碼lacth_spins.sql在例3.3中顯示了自旋對每種閂的效果。

例3.3 latch_spins.sql指令碼輸出樣式:

SQL> @latch_spins

LATCH TYPE                   SPIN    GETS SLEEP GETS SPIN HIT RATE
_________________________________________________________________

cache buffers lru chain             44752     182595        19.68%
redo allocation                     29218      66781        30.44%
library cache                       18997      43535        30.38%
cache buffers chains                11812      36001        24.70%
redo copy                             606      18245         3.21%
messages                             3968       8315        32.30%
enqueue hash chains                  1139       6603        14.71%
system commit number                 2312       5548        29.41%
undo global data                      252       1327        15.96%
session idle bit                      256       1198        17.61%
enqueues                              165        861        16.08%
transaction allocation                 80        535        13.01%
list of block allocation               47        353        11.75%
shared pool                           272        295        47.97%
dml lock allocation                    36        199        15.32%
global tx hash mapping                 36        184        16.36%
latch wait list                        27         95        22.13%
session allocation                     13         78        14.29%
row cache objects                      89         76        53.94%

ALL LATCHES                        114080     372833        23.43%

相關文章