天天看點

深入Log Buffer分析

資料庫在運作過程中,不可避免地要遇到各種能夠導緻資料庫損壞的情況。比如突然斷電、Oracle或者作業系統的程式bug導緻資料庫内部邏輯結構損壞、磁盤媒體損壞等,都有可能造成資料庫崩潰,進而導緻資料丢失的現象發生。

   為了避免,或者說為了修複這些狀況所導緻的資料丢失現象,Oracle引入了日志緩沖區和日志檔案的概念。所謂日志,就是将資料庫中所有改變資料塊的操作,都原原本本地記錄下來。這些改變資料塊的操作不僅包括對資料表的DML指令或者引起資料字典内容變化的DDL指令,還包括對索引的改變、對復原段資料塊的改變等。隻有将資料庫中所有的變化都記錄下來,當發生資料庫損壞時,才能夠通過重新應用這些變化,進而達到恢複資料庫的目的。

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

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

  第二種方式是使用實體的記錄方式,也就是将每個資料塊改變前的鏡像和改變後的鏡像都記錄下來。這種方式優點就是恢複起來速度非常快,直接根據日志檔案裡所記錄的資料塊位址和内容更新資料檔案中對應的資料塊。但是缺點也很明顯,就是非常占用磁盤空間。

  而Oracle在記錄日志的方式上,采用了邏輯和實體相結合的方式。也就是說,Oracle針對每個資料塊,記錄了插入某個值或者删除某個值的描述語句。假如某個update更新了100個資料塊,則Oracle會針對每個資料塊記錄一對delete 舊值和insert 新值的語句,共有100對這樣的描述語句。在每一對描述語句中,都記錄了相關資料塊的實體位址。通過這種邏輯與實體相結合的方式,Oracle在記錄變化時能夠盡量節省空間,同時在應用變化時,又能比較快速。

  為了臨時存放所産生的日志資訊,Oracle在SGA中開辟了一塊記憶體區域。這塊區域就叫做日志緩沖區(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;

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

  聯機日志檔案就是日志緩沖區的完全副本,組成日志檔案的每個日志塊的内容都來自于日志緩沖區的日志塊。每個日志緩沖區中的日志塊都對應到日志檔案中的一個日志塊。日志緩沖區中的日志塊按照發生的先後順序,放入聯機日志檔案。

  由于日志檔案在故障恢複中的重要性,建議至少使用兩個日志檔案組成一個日志檔案組。同一個日志檔案組中的日志檔案内容一模一樣,因為日志緩沖區中的日志塊同時會寫入日志檔案組中的每個日志檔案中。每個資料庫都必須至少擁有兩個日志檔案組。這是由于隻要資料庫一天不停止運作,就會不斷産生日志資訊,就會不斷寫入聯機日志檔案,聯機日志檔案總會有寫滿的時候。我們不可能讓聯機日志檔案無限大,也不可能放無限多的聯機日志檔案,是以聯機日志檔案必須是循環使用的,在若幹個日志檔案中輪流的進行寫入。一個日志檔案寫滿以後轉換到另外一個日志檔案繼續寫的過程叫做日志切換(log switch)。

  當一個聯機日志檔案寫滿時,可以選擇将其歸檔為脫機日志檔案,通常叫做歸檔日志檔案。歸檔也就是副本,歸檔的過程也就是将寫滿的聯機日志檔案複制到預先指定的目錄的過程。隻有當一個聯機日志檔案完成歸檔以後,該聯機日志檔案才能夠被再次循環使用。強烈建議在生産庫中選擇這種歸檔方式,隻有在測試環境中可以選擇不歸檔。

  可以說,日志緩沖區和日志檔案存在的唯一目的就是為了保證被修改的資料不會被丢失。反過來說,也就是為了能夠在資料庫崩潰的時候,可以用來将資料庫恢複到崩潰的那個時間點上。這也就是說,隻有将被修改的資料塊的日志資訊寫入了聯機日志檔案以後,該被修改的資料塊才可以說是安全的。如果日志資訊在沒有被寫入日志檔案時發生執行個體崩潰,這時對資料的修改仍将丢失。由此我們可以看出,将日志緩沖區中的日志資訊寫入日志檔案是一個非常重要的過程,這個過程是由一個名為LGWR的背景程序完成的。LGWR 承擔了維護系統資料完整性的任務,它保證了資料在任何情況下都不會丢失。

  觸發LGWR程序将日志緩沖區中的日志資訊寫入聯機日志檔案條件包括以下幾種。

 前台程序觸發,包括兩種情況。最顯而易見的一種情況就是使用者發出commit或rollback語句進行送出時,需要觸發LGWR将記憶體裡的日志資訊寫入聯機日志檔案,因為送出的資料必須被保護而不被丢失;另外一種情況就是在日志緩沖區中找不到足夠的記憶體來放日志資訊時,也會觸發LGWR程序将一些日志資訊寫入聯機日志檔案以後,進而釋放一些空間。

 每隔三秒鐘,LGWR啟動一次。

 在DBWn啟動時,如果發現髒資料塊所對應的重做條目還沒有寫入聯機日志檔案,則DBWn觸發LGWR程序并等待LRWR寫完以後才會繼續。

 日志資訊的數量達到整個日志緩沖區的1/3時,觸發LGWR。

 日志資訊的數量達到1MB時,觸發LGWR。

oracle視訊教程請關注:http://down.51cto.com/4202939/up