<b>背景</b>
innodb作為事務性引擎,使用write-ahead logging(wal)機制保證acid中的atomicity和durability,使用undo機制保證acid中的consistency和isolation。
按照wal和undo的機制,形成以下兩個原則:
<dl></dl>
<dd>1. 資料塊的更改需要先記錄redo日志。</dd>
<dd>2. 資料塊的更改需要先寫入undo。</dd>
根據這兩個原則,innodb更新資料的基本流程可以簡單的總結為:
<dd>1. 記錄需要更改undo record的redo log</dd>
<dd>2. 記錄需要更改data record的redo log</dd>
<dd>3. 寫入redo log</dd>
<dd>4. 寫入undo record</dd>
<dd>5. 更新data record</dd>
這5個步驟。
<b>innodb recovery</b>
如果mysql執行個體異常crash,那麼重新開機過程中首先會進行innodb recovery。 即:根據last checkpoint點,順序讀取後面的redo log,按照先前滾,再復原的原則, 應用所有的redo log。
因為redo record中記錄着資料塊的位址(space_id+page_no),是以recovery的過程首先會執行合并相同資料塊的操作,以加快recovery的過程。
<b>那麼問題來了</b>
<dl><dd>根據space_id怎麼找到對應idb資料檔案?</dd></dl>
因為在恢複的過程中,innodb隻load了redo檔案和系統表空間檔案,如何查找innodb的資料檔案呢?
<dd>1. innodb的資料字典dict_table_t結構中也儲存了對應關系,但資料字典受redo保護,recovery的過程中不可用。</dd>
<dd>2. 掃描datadir的所有資料檔案,讀取page中儲存的space_id,建立space_id和資料檔案的對應關系。</dd>
mysql目前采用第二種方式,但帶來了一個問題,當設定了innodb_file_per_table後,每一個表對應一個表空間,那麼需要讀取所有的目錄下的所有innodb資料檔案,這樣就會嚴重的影響了recovery的時間。
<b>mysql 5.7改進政策:</b>
mysql 5.7中,在redo log中增加了一種新的record類型,即mlog_file_name,記錄了自last checkpoint以來更改的資料檔案的file name。 這樣在應用的時候,直接根據檔案名就可以找到資料檔案。
<b>oracle的設計機制:</b>
oracle資料庫recovery的過程中,有沒有這個問題呢? 答案是沒有。
我們來看下oracle的設計機制:
<dl><dd>oracle同樣在系統表空間中記錄了資料字典,受redo保護,可以通過dba_開頭的表來查詢。但oracle還維護了一個control file,控制檔案中記錄了database name,redo file,datafile,backup等資訊,通過v$開頭的表查詢。</dd></dl>
<dl><dd>當oracle在recovery的過程中,需要資料庫在mount狀态下,即打開了控制檔案,這時資料字典還不可用(db沒有open),在應用redo log的時候,根據控制檔案中的v$datafile,檢索file_id和file_name的對應關系。</dd></dl>
mysql是根據datadir,innodb_data_home_dir,innodb_log_group_home_dir等幾個目錄配置,通過檔案系統的查找,找到相應檔案的,而oracle維護了一個集中式的control file管理這些初始加載的檔案位址。