InnoDB儲存引擎檔案

readyao發表於2017-03-18

MySql中每個表儲存引擎都有自己獨有的檔案,InnoDB儲存引擎相關的檔案主要包括:重做日誌檔案,表空間檔案。

1、表空間檔案

InnoDB採用將儲存的資料按表空間(tablespace)進行存放的設計。在預設配置下會有一個初始大小為10MB,名為ibdata1的檔案。該檔案就是預設的表空間檔案(tablespace file),使用者可以通過引數innodb_data_file_path對其進行設定.

mysql> show variables like 'innodb_data_file_path';
+-----------------------+------------------------+
| Variable_name         | Value                  |
+-----------------------+------------------------+
| innodb_data_file_path | ibdata1:10M:autoextend |
+-----------------------+------------------------+
1 row in set (0.00 sec)

使用者可以通過多個檔案組成一個表空間,同時制定檔案的屬性。
innodb_data_file_path=/db/ibdata1:200M;/dr2/db/ibdata2:2000M:autoextend
這裡/db/ibdata1和/dr2/db/ibdata2兩個檔案用來組成表空間。若這兩個檔案位於不同的磁碟上,磁碟的負載可能被平均,因此可以提高資料庫的整體效能。同時,兩個檔案的檔名後都跟了屬性,表示檔案ibdata1大小為200M, ibdata2大小為20000M,如果用完了這2000M,該檔案可以自動增長(autoextend)。

設定innodb_data_file_path引數後,所有基於InnoDB儲存引擎的表的資料都會記錄到該共享表空間中。若設定了擦拭農戶innodb_file_per_table,則使用者可以將每個基於InnoDB儲存引擎的表產生一個獨立表空間。
獨立表空間的命名規則為:表名.ibd。通過這樣的方式,使用者不用將所有資料都存放於預設的表空間中。
這些單獨的表空間僅僅儲存該表的資料、索引和插入緩衝BITMAP等資訊,其餘資訊還是存放在預設的表空間中。
預設該引數是關閉的。

mysql> show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | OFF   |
+-----------------------+-------+
1 row in set (0.00 sec)

下圖顯示了InnoDB儲存引擎對於檔案的儲存方式:
這裡寫圖片描述

2、重做日誌檔案

在預設情況下,在InnoDB儲存引擎的資料目錄下會有兩個名為ib_logfile0和ib_logfile1的檔案。在MySql官方手冊中將其稱為InnoDB儲存引擎的日誌檔案,不過更準確的定義應該是重做日誌檔案(redo log file)。
重做日誌檔案對於InnoDB儲存引擎很重要,它們記錄了對於InnoDB儲存引擎的事務日誌。

當例項或介質(media failure)時,重做日誌檔案就派上用場了。例如,資料庫由於所在主機掉電導致例項失敗,InnoDB儲存引擎會使用重做日誌恢復到掉電前的時刻,以此來保證資料的完整性。

每個InnoDB儲存引擎至少有1個重做日誌檔案組,每個檔案組下至少有2個重做日誌檔案,如預設的ib_logfile0和ib_logfile1。

root@TryHard:~# find / -name ib_logfile*;
/var/lib/mysql/ib_logfile1
/var/lib/mysql/ib_logfile0

為了得到更高的可靠性,使用者可以設定多個映象日誌組,將不同的檔案組放在不同的磁碟上,以此提高日誌的高可用性。在日誌組中每個重做日誌檔案的大小一致,並以迴圈寫入的方式執行。InnoDB儲存引擎先寫重做日誌檔案1,當達到檔案的最後時,會切換至重做日誌檔案2,再當重做日誌檔案2也被寫滿時,會再切換到重做日誌檔案1中。下圖顯示了一個擁有3個重做日誌檔案的重做日誌檔案組。
這裡寫圖片描述

下面引數影響著重做日誌檔案的屬性:
(1)innodb_log_file_size
(2)innodb_log_files_in_group
(3)innodb_mirrored_log_groups
(4)innodb_log_group_home_dir

引數innodb_log_file_size指定每個重做日誌檔案的大小。在InnoDB1.2.x版本之前,重做日誌檔案總的大小不得大於等於4GB,而1.2.x版本將該顯示擴大為512GB。
引數innodb_log_files_in_group指定了日誌檔案組中重做日誌檔案的數量,預設為2.
引數innodb_mirrored_log_groups指定了日誌映象檔案組的數量,預設為1,表示只有一個日誌檔案組,沒有映象。如果磁碟本身已經做了高可用的方案,如磁碟陣列,那麼可以不開啟重做日誌映象的功能。
引數innodb_log_goup_home_dir指定了日誌檔案組所在路徑,預設為./,表示在MySql資料庫的資料目錄下。

mysql> show variables like 'innodb%log%';
+--------------------------------+---------+
| Variable_name                  | Value   |
+--------------------------------+---------+
| innodb_flush_log_at_trx_commit | 1       |
| innodb_locks_unsafe_for_binlog | OFF     |
| innodb_log_buffer_size         | 8388608 |
| innodb_log_file_size           | 5242880 |
| innodb_log_files_in_group      | 2       |
| innodb_log_group_home_dir      | ./      |
| innodb_mirrored_log_groups     | 1       |
+--------------------------------+---------+
7 rows in set (0.00 sec)

重做日誌檔案的大小設定對於InnoDB儲存引擎的效能有著非常大的影響。一方面重做日誌不能設定的太大。如果設定的很大,在恢復時可能需要很長的時間;另一方面又不能設定的太小了,否則可能導致一個事務的日誌需要多次切換重做日誌檔案。此外,重做日誌檔案太小會導致頻繁地發生async checkpoint,導致效能的抖動。
因為重做日誌有一個capacity變數,該值代表了最後的檢查點不能超過這個閥值,如果超過則必須將緩衝池中髒頁列表中的部分髒資料頁寫回磁碟,這時會導致使用者執行緒的阻塞。


重做日誌也是記錄事務日誌,那麼它和二進位制日誌有什麼區別?

首先,二進位制日誌會記錄所有與MySql資料庫有關的日誌記錄,包括InnoDB,MyISAM,Heap等其它儲存引擎的日誌。而InnoDB儲存引擎的重做日誌只記錄有關該儲存引擎本身的事務日誌。

其次,記錄的內容不同。無論使用者將二進位制日誌檔案記錄的格式設定為STATEMENT還是ROW,又或者是MIXED,其記錄的都是關於一個事務的具體操作內容,即該日誌是邏輯日誌。而InnoDB儲存引擎的重做日誌檔案記錄的是關於每個頁的更改的物理情況。

最後,寫入的時間也不同,二進位制日誌檔案僅在事務提交前進行提交,即只寫磁碟一次,不論這時該事務多大。而在事務進行的過程中,卻不斷有重做日誌條目被寫入重做日誌檔案中。

在InnoDB儲存引擎中,對於各種不同的操作有著不同的重做日誌格式。到InnoDB1.2.x版本為止,總共定義了51種重做日誌型別。雖然各種重做日誌的型別不同,但是他們有著基本的格式,下表顯示了重做日誌條目的結構:
這裡寫圖片描述
重做日誌條目由4個部分組成:
redo_log_type佔用1個位元組,表示重做日誌的型別。
space表示表空間的ID,但採用壓縮的方式,因此佔用的空間可能小於4位元組。
page_no表示頁的偏移量,同樣採用壓縮的方式
redo_log_body表示每個重做日誌的資料部分,恢復時需要呼叫相應的函式進行解析。

寫入重做日誌檔案的操作不是直接寫,而是先寫入一個重做日誌緩衝(redo log buffer)中,然後按照一定的條件順序地寫入日誌檔案。下圖顯示了重做日誌的寫入過程。
這裡寫圖片描述

從重做日誌緩衝往磁碟寫入時,是按512位元組,也就是一個扇區的大小進行寫入。因為扇區是寫入的最小單位,因此可以保證寫入必定是成功的。因此在重做日誌的寫入過程中不需要有doublewrite。


前面說,從日誌緩衝寫入磁碟上的重做日誌檔案是按一定條件進行的,那麼這些條件有哪些呢?
主執行緒每秒會將重做日誌緩衝寫入磁碟的重做日誌檔案中,不論事務是否已經提交。
另一個觸發寫磁碟的過程是由引數innodb_flush_log_at_trx_commit控制,表示在提交操作時,處理重做日誌的方式。

mysql> show variables like 'innodb_flush_log_at_trx_commit';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1     |
+--------------------------------+-------+
1 row in set (0.00 sec)

引數innodb_flush_log_at_trx_commit的有效值有0,1,2。
0代表當前提交事務時,並不將事務的重做日誌寫入磁碟上的日誌檔案,而是等待主執行緒每秒的重新整理。
1和2不同的地方在於:1表示在執行commit時將重做日誌緩衝同步寫到磁碟,即伴有fsync的呼叫。2表示將重做日誌非同步寫到磁碟,即寫到檔案系統的快取中。因此不能完全保證在執行commit時肯定會寫入重做日誌檔案,只是有這個動作發生。

因此為了保證事務的ACID中的永續性,必須將innodb_flush_log_at_trx_commit設定為1,也就是每當有事務提交時,就必須確保事務都已經寫入重做日誌檔案。那麼當資料庫因為意外發生當機時,可以通過重做日誌檔案恢復,並保證可以恢復已經提交的事務。而設定為0或2,都有可能發生恢復時部分事務的丟失。不同之處在於,設定為2時,當MySql資料庫發生當機而作業系統及伺服器並沒有發生當機時,由於此時未寫入磁碟的事務日誌儲存在檔案系統快取中,當恢復時同樣能保證資料不丟失。


總結
InnoDB儲存引擎相關的檔案,包括表空間檔案和重做日誌檔案。表空間檔案是用來管理InnoDB儲存引擎的儲存,分為共享表空間和獨立表空間。
重做日誌非常的重要,用來記錄InnoDB儲存引擎的事務日誌,也因為重做日誌的存在,才使得InnoDB儲存引擎可以提供可靠的事務。

相關文章