buffer cache實驗9-從buffer caceh中讀取資料區塊解析-從邏輯讀到物理讀

來源:互聯網
上載者:User

先來張大圖:


 

所用SQL語句:
BYS@ ocm1>select dbms_rowid.rowid_relative_fno(rowid) file#,dbms_rowid.rowid_block_number(rowid) block#,deptno from bys.test;
     FILE#     BLOCK#     DEPTNO
---------- ---------- ----------
         4        391         10
就以為例,文字描述分析一下前台進程發出查詢語句時擷取所需資料區塊的過程: 註:本文不涉及SQL語句的解析部分、用戶端與伺服器互動等,只涉及buffer cache。
這裡的物理讀是非直接路徑讀、非大表全表掃描--此點最後會有介紹。
如果發出的是更新語句,只是在buffer pin上所加的鎖為X獨佔鎖,其它步驟基本一致。
本文的例子唯讀取了一個資料區塊。
從buffer cache中讀取一個資料區塊一般需要100ns左右,從一般的儲存硬碟中讀取一個資料區塊需要10ms;所以大概算一下,從記憶體中讀取資料區塊比從硬碟中快近十萬倍。
故oracle在讀取資料區塊時,先在buffer cache中尋找,如存在,則讀取--邏輯讀;如果資料區塊不存在,則發生物理讀,從物理檔案中將資料讀入buffer cache(不考慮直接讀的情況)。
之前寫過的邏輯讀的: 資料讀取之邏輯讀簡單解析--關於BUFFER CACHE
下面正式開始:--首先是邏輯讀的過程 1.前台進程發出查詢語句select deptno from bys.test;
2.根據DBA計算HASH值,根據HASH值找到相應的Hash bucket
3.擷取CBC LATCH,如擷取失敗,則將產生:latch:cache buffers chains
4.在CBC LATCH保護下,伺服器處理序掃描hash chain,尋找是否有所需BH
5.如尋找到所需BH,將在Buffer Header上加buffer pin鎖(這裡是讀操作所以是共用鎖定(找到BH時的鎖常見有:當前讀鎖、一致讀鎖或修改鎖),如擷取buffer pin失敗(比如正在X模式申請S模式),會產生buffer busy waits等待),並根據BH中指定的塊在記憶體中實際地址,讀取buffer,並將結果返回前台進程。讀取完畢(納秒級)後,將再次擷取CBC LATCH,釋放buffer pin鎖,再釋放CBC LATCH。 
-----以上為邏輯讀,如果未找到buffer,將發生如下的物理讀: 6.如果未尋找到所需BH,將發生物理讀。伺服器處理序將從磁碟上的相應資料檔案中讀取所需塊,並將此塊讀入buffer cche中。
7.將塊讀入buffer cache中時,如何找到一個可以使用的buffer呢?下面步驟進行一步步解析。
8.首先在輔助LRU的最尾端向前尋找可用buffer,TCH<2的塊可以被重用。
9.如果輔助LRU最尾端的塊是TCH<2的塊,則將直接使用此塊,並將其移動到主LRU的冷端頭。
同時也會根據此塊的DBA進行HASH,尋找相應的HASH BUCKET,將此塊加入到對應的HASH CHAIN上,並對BH中的相應資訊進行修改(如對應X$BH中的LRU_FLAG,NXT_HASH、BA等欄位的具體值)--此過程也需要相應的CBC LATCH /buffer pin鎖的擷取釋放等。
再把資料區塊的值返回前台進程,此時物理讀就完成了。
10.如果輔助LRU最尾端的塊是TCH>=2的塊,則首先將此塊移動到主LRU的熱端頭,同時TCH清零;然後在在輔助LRU上繼續向前尋找,直到找到可用的塊---TCH<2。 之後的過程和步驟9中的就一樣了。(SMON每三秒時,伺服器處理序掃描空閑BUFFER時;都會把輔助LRU中TCH大於等於2的移到主的熱端頭)
11.如果在輔助LRU上搜尋完畢扔未找到可以使用的塊,則將從主LRU的冷端尾開始搜尋。
12.如果主LRU最尾端的塊是TCH<2的塊,則將直接使用此塊,並將其移動到主LRU的冷端頭,TCH為1。如是TCH>=2的塊,則將其移動到熱端頭,TCH清零。如果是髒塊,則將其移動到主LRUW上。依此規則向前搜尋尋找可用塊。(SMON每3秒,從主LRU冷端尋找TCH小於2的非髒塊到輔助LRU確保輔助LRU中有可用BUFFER)
13.如果從主LRU最尾端向前搜尋了40%(隱含參數_db_block_max_scan_pct,)還未找到可用塊,則將觸發DBWR寫LRUW上的髒塊--(CKPTQ隊列的寫不涉及LRUW, 只有DBWR會寫LRUW上髒塊,並且寫的是LRUW上的全部髒塊-每三秒醒來也要全部寫出LRUM上所有塊才會休眠。寫LRUW上髒塊的步驟是:DBWR進程寫時或者SMON進程每三秒醒來時(LRUW進程不像輔助LRUW那樣,非DBWR進程也允許訪問),會將主LRUW上的一部分髒塊移動到輔助LRUW,然後在輔助LRUW上排序、寫入磁碟;然後再從主LRUW上移動下一批,直到寫出完畢再次進入睡眠。並且在DBWR寫出過程中,會產生free buffer waits),寫出後的buffer將重新掛載到輔助LRU上並變為可用。

關於大表全表掃描及_small_table_threshold   參數的說明:大小表的界限是:_small_table_threshold,此參數中的VALUE 是資料區塊個數。
大表的全表掃描只使用輔助LRU,其塊的TCH為1。這樣做不對主LRU上的塊進行衝擊,同時也方便大表中塊的重用。此時如有其它使用者語句需要從輔助LRU上尋找可用buffer,直接可以使用,節約時間。
小表的全表掃描和普通資料區塊一樣來尋找可用buffer.


P_NAME                                   P_DESCRIPTION                                      P_VALUE                        ISDEFAULT ISMODIFIED ISADJ
---------------------------------------- -------------------------------------------------- ------------------------------ --------- ---------- -----
_small_table_threshold                   lower threshold level of table size for direct rea 89                             TRUE      FALSE    FALSE
                                         ds
這裡的89是BLOCK數量,表所使用的BLOCK的數量--不是直接的MB或者KB。。
_small_table_threshold的值在資料庫啟動的時候自動設定成BUFFER數量的2%。--可以修改buffer cache大小並重啟資料庫驗證。
SYS@ bys3>select count(*)*0.02 from x$bh;   ---從X$BH中擷取BUFFER的數量
COUNT(*)*0.02
-------------
        88.98


關於直接路徑讀的說明: ---來自百度直接路徑讀(direct path read)通常發生在Oracle直接讀資料到進程PGA時,這個讀取不需要經過SGA。直接路徑讀等待事件的3個參數分別是file number(指絕對檔案號)、first dba、block cnt數量。在Oracle 10g/11g中,這個等待事件被歸於User I/O一類。db file sequential read、db file scattered read、direct path read 是常見的集中資料讀方式。

在資料倉儲環境大量的direct path read是正常的。在OLTP中,大量direct path read意味應用有問題導致大量磁碟排序讀取操作。

最為常見的是第一種情況。在DSS系統中,存在大量的direct path read是很正常的,但是在OLTP系統中,通常顯著的直接路徑讀(direct path read)都意味著系統應用存在問題,從而導致大量的磁碟排序讀取操作。直接路徑寫(direct paht write)通常發生在Oracle直接從PGA寫資料到資料檔案或臨時檔案,這個寫操作可以繞過SGA。直接路徑寫等待事件的3個參數分別是:file number(指絕對檔案號)、first dba和block cnt數量,在Oracle 10g/11g中,這個等待事件同direct path read一樣被歸於User I/O一類。這類寫入操作通常在以下情況被使用:·直接路徑載入;·並行DML操作;·磁碟排序;·對未緩衝的“LOB”段的寫入,隨後會記錄為direct path write(lob)等待。最為常見的直接路徑寫,多數因為磁碟排序導致。對於這一寫入等待,我們應該找到I/O操作最為頻繁的資料檔案(如果有過多的排序操作,很有可能就是臨時檔案),分散負載,加快其寫入操作。

直接路徑插入時,不產生表塊的復原資訊,而是依賴高水位點實現復原
但是,如果表有索引,將會產生索引的復原資訊,而且索引的塊會被讀進buffer cache
Oracle官方文檔建議,如果使用直接路徑插入,向表中傳送大量資料,可先將表上的索引刪掉,插入結束後,再重建立立索引

在Oracle 11g版本中串列的全表掃描可能使用直接路徑讀取(direct path read)的方式取代之前版本中一直使用的DB FILE SCATTERED READ, 顯然direct path read具備更多的優勢:

1. 減少了對latch爭用

2.物理IO的大小不再取決於buffer_cache中所存在的塊;
試想某個8個塊的extent中1,3,5,7號塊在快取中,而2,4,6,8塊沒有被緩衝,傳統的方式在讀取該extent時將會是對2,4,6,8塊進行4次db file sequential read,其效率往往要比單次讀取這個區間的所有8個塊還要低得多,
而direct path read則可以完全避免這類問題,儘可能地單次讀入更多的物理塊。

當然直接路徑讀取也會引入一些缺點:
1.在直接路徑讀取某段前需要對該對象進行一次段級的檢查點(A segment checkpoint).
2.可能導致重複的延遲塊清除操作
http://www.oracledatabase12g.com/archives/direct-read-impact-on-delayed-block-read.html


相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.