log buffer及日誌管理深入分析及效能調整(一)

531968912發表於2015-02-27

的概念

概述

在執行過程中,不可避免的要遇到各種能夠導致資料塊庫損壞的情況。比如突然斷電、

或者作業系統的程式bug導致資料庫內部邏輯結構損壞、磁碟介質損壞等,都有可能造成資料庫崩潰,從而導致資料丟失的現象發生。

      為了避免,或者說為了修復這些狀況所導致的資料丟失現象,oracle引入了日誌緩衝區和日誌檔案的概念。所謂日誌,就是將所有資料庫中所有改變資料塊的操作,都原原本本的記錄下來。這些改變資料塊的操作不僅包括對資料表的DML或者對資料字典的DDL,還包括對索引的改變、對回滾段資料塊的改變、對臨時表空間的臨時段的改變等。只有將資料庫中所有的變化都記錄下來,當發生資料庫損壞時,才能夠從損壞時的那一點開始,將之後資料庫中的變化重新運用一遍,從而達到恢復資料庫的目的。

      既然是要記錄,那就必然引出一個問題,就是如何記錄這些變化?比較容易想到的有兩種方式。

第一種是使用邏輯的記錄方式,也就是用描述性的語句來記錄整個變化過程。比如對於某個update更新操作來說來說,可以記錄為兩條語句:delete舊值以及insert新值。這種方式的優點是非常節省空間,因為對每個操作,只需要記錄幾條邏輯上的語句即可。但是缺點也很明顯,就是一旦需要進行恢復,就會非常消耗資源。設想一下,某個update操作更新了非常多的資料塊,由於buffer cache記憶體有限,很多髒資料塊都已經寫入了資料檔案。但就在更新快結束時,突然發生斷電,所做的更新丟失。那麼重新啟動例項時,oracle需要應用日誌檔案裡的記錄,於是重新發出delete舊值以及insert新值的語句。這個過程需要重新查詢資料檔案中符合條件的資料塊,然後再挑出來進行更新。這個過程將非常消耗時間,而且會佔用大量的buffer cache

      第二種方式是使用物理的記錄方式,也就是將每個資料塊改變前的映象和改變後的映象都記錄下來。這種方式優點就是恢復起來速度非常快,直接根據日誌檔案裡所記錄的資料塊地址和內容更新資料檔案中對應的資料塊。但是缺點也很明顯,就是非常佔用磁碟空間。

      oracle在記錄日誌的方式上,採用了邏輯和物理相結合的方式。也就是說,oracle針對每個資料塊,記錄了插入某個值或者刪除某個值的描述語句。假如某個update更新了100個資料塊,則oracle會針對每個資料塊記錄一對delete舊值和insert新值的語句,共有100對這樣的描述語句。透過這種方式,oracle獲得了物理記錄方式的快速恢復的優點,同時又獲得了邏輯記錄方式的節省空間的優點。

      為了臨時存放所產生的日誌資訊,oracleSGA中開闢了一塊記憶體區域。這塊區域就叫做日誌緩衝區(log buffer),當滿足一定條件以後,oracle會使用名為LGWR的後臺程式將log buffer中的日誌資訊寫入聯機日誌檔案裡。

      可以使用初始化引數log_buffer來設定日誌緩衝區的大小,單位是位元組。日誌緩衝區會進一步細分為多個塊,每個塊的尺寸與作業系統的一個塊的尺寸相同,基本都是512位元組。我們可以用如下方式來獲得日誌緩衝區的塊尺寸。

SQL> select distinct lebsz as redo_block_size from x$kccle;

REDO_BLOCK_SIZE

---------------

           512

也可以用下面的方式來計算出日誌緩衝區的塊尺寸。

SQL> select round((a.redosize+b.redowast)/c.redoblks) + 16 as redo_block_size from

 2 (select value redosize from v$sysstat where name='redo size') a,

 3 (select value redowast from v$sysstat where name='redo wastage') b,

 4 (select value redoblks from v$sysstat where name='redo blocks written') c

 5 ;

REDO_BLOCK_SIZE

---------------

           512

日誌緩衝區只是日誌資訊臨時存放的區域,這塊區域是有限的,而且其中的每個塊都是能夠迴圈使用的。這也就說明,日誌緩衝區中的內容必須要寫入磁碟上的檔案裡,才能永久保留下來,才能在資料庫崩潰時能夠用來進行恢復。這個檔案就叫做聯機日誌檔案。在每個日誌緩衝區中的日誌塊被重用之前,其內容必然已經被寫入了磁碟上的聯機日誌檔案中。

聯機日誌檔案就是日誌緩衝區的完全複製,組成日誌檔案的每個日誌塊的內容都來自於日誌緩衝區的日誌塊。每個日誌緩衝區中的日誌塊都對應到日誌檔案中的一個日誌塊。日誌緩衝區中的日誌塊按照發生的先後順序,放入聯機日誌檔案。由於日誌檔案在故障恢復中的重要性,建議至少使用兩個日誌檔案組成一個日誌檔案組。同一個日誌檔案組中的日誌檔案內容一摸一樣,因為日誌緩衝區中的日誌塊同時會寫入日誌檔案組中的每個日誌檔案中。每個資料庫都必須至少擁有兩個日誌檔案組。這是由於只要資料庫一天不停止執行,就會不斷產生日誌資訊,就會不斷寫入聯機日誌檔案,聯機日誌檔案總會有寫滿的時候。我們不可能讓聯機日誌檔案無限大,也不可能放無限多的聯機日誌檔案,所以聯機日誌檔案必須是迴圈使用的,在若干個日誌檔案中輪流的進行寫入。一個日誌檔案寫滿以後轉換到另外一個日誌檔案繼續寫的過程叫做日誌切換(log switch)。

當一個聯機日誌檔案寫滿時,可以選擇將其歸檔為離線日誌檔案,通常叫做歸檔日誌檔案。歸檔也就是複製,歸檔的過程也就是將寫滿的聯機日誌檔案複製到預先指定的目錄的過程。只有當一個聯機日誌檔案完成歸檔以後,該聯機日誌檔案才能夠被再次迴圈使用。強烈建議在生產庫中選擇這種歸檔方式,只有在測試環境中可以不選擇這種歸檔方式。

可以說,日誌緩衝區和日誌檔案存在的唯一目的就是為了保證被修改的資料不會被丟失。反過來說,也就是為了能夠在資料庫崩潰的時候,可以用來將資料庫恢復到崩潰的那個時間點上。這也就是說,只有將被修改的資料塊的日誌資訊寫入了聯機日誌檔案以後,該被修改的資料塊才可以說是安全的。如果日誌資訊在沒有被寫入日誌檔案時發生例項崩潰,這時對資料的修改仍將丟失。由此我們可以看出,將日誌緩衝區中的日誌資訊寫入日誌檔案是一個多麼重要的過程,這個過程是由一個名為LGWR的後臺程式完成的。LGWR承擔了維護系統資料完整性的任務,它保證了資料在任何情況下都不會丟失。

觸發LGWR程式將日誌緩衝區中的日誌資訊寫入聯機日誌檔案條件包括以下幾種:

<!--[if !supportLists]--&gt1)     <!--[endif]--&gt前臺程式觸發,包括兩種情況。最顯而易見的一種情況就是使用者發出commitrollback語句進行提交時,需要觸發LGWR將記憶體裡的日誌資訊寫入聯機日誌檔案,因為提交的資料必須被保護而不被丟失;另外一種情況就是在日誌緩衝區中找不到足夠的記憶體來放日誌資訊時,也會觸發LGWR程式將一些日誌資訊寫入聯機日誌檔案以後,從而釋放一些空間出來。

<!--[if !supportLists]--&gt2)     <!--[endif]--&gt每隔三秒鐘,LGWR啟動一次。

<!--[if !supportLists]--&gt3)     <!--[endif]--&gtDBWR啟動時,如果發現髒資料塊所對應的重做條目還沒有寫入聯機日誌檔案,則DBWR觸發LGWR程式並等待LRWR寫完以後才會繼續。

<!--[if !supportLists]--&gt4)     <!--[endif]--&gt日誌資訊的數量達到整個日誌緩衝區的1/3時,觸發LGWR

<!--[if !supportLists]--&gt5)     <!--[endif]--&gt日誌資訊的數量達到1MB時,觸發LGWR

<!--[if !supportLists]--&gt6)     <!--[endif]--&gt發生日誌切換時觸發LGWR

的記憶體結構

我們已經知道,日誌緩衝區用來存放事務對資料塊的改變的日誌資訊。那麼這裡的日誌資訊到底包含哪些內容,是由哪些結構組成的呢?

oracle記錄資料庫變化(也就是記錄日誌資訊)的最小單位是改動向量(change vector)。改動向量用來描述對資料庫中任何單個資料塊所做的一次改動。改動向量的內容包括:被改動的資料塊的版本號、事務操作程式碼、被改動的資料塊的地址等。這裡的版本號非常重要,它能夠幫助資料塊始終能夠體現當前最新的狀態。oracle在建立改動向量時,會從資料塊中複製其版本號。而當恢復期間,oracle讀取改動向量並將改動應用於相應的資料塊以後,被恢復的資料塊的版本號加1。這裡的資料塊可以屬於表、也可以資料索引、也可以屬於回滾段。但是對於臨時表空間裡的臨時段,不會生成改動向量。

當多個改動向量按照先後順序組合在一起,從而完成對資料庫的一次改動時,oracle稱這組改動向量為重做記錄(redo record)。重做記錄用來描述對資料庫的一個原子改動。所謂原子改動,就是說,當應用改動中的改動向量時,要麼全部成功,要麼全部失敗,不存在部分成功部分失敗的情況。重做記錄能夠幫助整個資料庫體現當前最新的狀態。

一個事務至少產生一個重做記錄,也可能產生多個重做記錄。而oracle在應用日誌記錄進行恢復的過程中,以事務作為恢復的最小單位。要麼恢復整個事務,要麼回滾整個事務。也就是說,要麼運用事務中的重做記錄裡的所有改動向量,要麼一個改動向量都不運用。

因此,日誌緩衝區就是許多重做記錄按照發生的先後順序組成的。同時,日誌檔案也就是由許多重做記錄按照先後順序排列在一起而組成的檔案。

我們舉個例項來說明重做記錄和改動向量產生的過程。比如我們發出如下更新語句(假設表redo_testname列上沒有建立索引):

SQL> select * from redo_test;

       ID NAME

---------- ----------

        1 abc

        2 abc

SQL> update redo_test set name='cdf' where id=1;

             該語句發出以後,會產生一個重做記錄,用來描述對錶的資料塊的修改。包括下面三個改動向量:

<!--[if !supportLists]--&gt1)     <!--[endif]--&gt對回滾段事務表的改動,這發生在回滾段段頭。事務表中包含被修改的資料塊的地址、該事務的狀態(commitactive)、以及存有該事務所使用的回滾段的地址。如果事務表被修改,就會產生針對於它的改動向量。

<!--[if !supportLists]--&gt2)     <!--[endif]--&gt對回滾段資料塊的改動。將修改前的舊值(abc)存放到回滾段的資料塊裡。這時回滾段發生改變,於是產生改動向量。

<!--[if !supportLists]--&gt3)     <!--[endif]--&gtredo_test表的資料塊所做的改動。將修改後的新值(cdf)存放到表的資料塊裡。這時資料塊發生改變,於是產生改動向量。

從這個例項可以知道,對於這個update事務,重做記錄中會有三個改動向量。當然可能有其他情況會產生新的重做記錄,比如修改的列如果有索引,則必須修改索引。這時就會產生第二個重做記錄,用來描述對索引資料塊的修改。這時候的重做記錄還是和第一個重做記錄一樣,包含多個改動向量。此外,在事務完成之後執行commitrollback語句時,就會產生第三個重做記錄。該重做記錄只有一個改動向量,用來記錄對回滾段事務表的更改,因為commitrollback時,需要更新事務表裡記錄的該事務的狀態。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25462274/viewspace-1442621/,如需轉載,請註明出處,否則將追究法律責任。

相關文章