MySQL InnoDB儲存引擎

2020-07-16 10:05:33
InnoDB 是 MySQL 中第一個提供外來鍵約束的儲存引擎,而且它對事務的處理能力是其它儲存引擎無法與之相比的。

MySQL 5.5 版本以後,預設儲存引擎由  MyISAM 修改為 InnoDB。InnoDB 是目前最重要、使用最廣泛的儲存引擎。

InnoDB 一直在持續改進,隨著處理能力的不斷提高,其優秀的效能和可維護性使它成為生產中普遍推薦使用的儲存引擎。一般情況下,除非有特別的原因需要使用其它儲存引擎,否則應該優先考慮 InnoDB 引擎。

下面從優勢和物理儲存結構兩個方面來講解 InnoDB 儲存引擎。

InnoDB優勢

InnoDB 之所以如此受寵,主要在於其功能方面的較多優勢。

1)支援事務安裝

InnoDB 最重要的一點就是支援事務,可以說這是 InnoDB 成為 MySQL 中最流行的儲存引擎的一個非常重要的原因。InnoDB 還實現了 SQL92 標準所定義的 4 個隔離級別(READ UNCOMMITTED,READ COMMITTED,REPEATABLE READ 和 SERIALIZABLE)。

InnoDB 對事務安全的支援,讓很多之前因為特殊業務而放棄使用 MySQL 的使用者轉向支援 MySQL。以及對資料庫選型持觀望態度的使用者來說,也大大增加了對 MySQL 的好感。

2)災難恢復性好

InnoDB 通過 commit、rollback、crash-recovery 來保障資料的安全。

具體來說,crash-recovery 就是指如果伺服器因為硬體或軟體的問題而崩潰,不管當時資料是怎樣的狀態,在重新啟動 MySQL 後,InnoDB 都會自動恢復到發生崩潰之前的狀態,並回到使用者離開的地方。

3)使用行級鎖

InnoDB 改變了 MyISAM 的鎖機制,實現了行鎖。雖然 InnoDB 的行鎖機制是通過索引來完成的,但畢竟在資料庫中 99%的 SQL 語句都要使用索引來檢索資料。行鎖定機制也為 InnoDB 在承受高並行壓力的環境下增強了不小的競爭力。

在 SQL 查詢中可以自由地將 InnoDB 型別的表與其他型別的表混合起來,甚至在同一個查詢中也可以混合。

4)實現了緩衝處理

InnoDB 提供了專門的快取池,實現了緩衝管理,不僅能緩衝索引也能緩衝資料,常用的資料可以直接從記憶體中處理,比從磁碟獲取資料處理速度要快。相比之下,MyISAM 只是快取了索引。

InnoDB 的表和索引在一個邏輯表空間中,表空間可以包含數個檔案(或原始磁碟分割區)。這與 MyISAM 表不同,比如在 MyISAM 表中每個表被儲存在分離的檔案中。InnoDB 表可以是任何尺寸,即使在檔案尺寸被限制為 2GB 的作業系統上。

5)支援外來鍵

InnoDB 支援外來鍵約束,檢查外來鍵、插入、更新和刪除,以確保資料的完整性。在儲存表中資料時每張表的儲存都按主鍵順序存放,如果沒有顯式地在定義表時指定主鍵,InnoDB 會為每一行生成一個 6 位元組的 ROWID ,並以此作為主鍵。

InnoDB 實現外來鍵參照這一重要特性,使在資料庫端控制部分資料的完整性成為可能。雖然很多資料庫系統調優專家都建議不要這樣做,但是對於不少使用者來說,大部分情況下,在資料庫端加外來鍵控制仍然是成本最低的選擇。

6)適合需要大型資料庫的網站

InnoDB 被用在眾多需要高效能的大型資料庫網站上。

InnoDB 是為處理巨巨量資料量時的最大效能設計,它的 CPU 效率可能是任何其他基於磁碟的關聯式資料庫引擎所不能匹敵的。

除了以上幾個亮點之外,InnoDB 常常還有很多其它的功能特色帶給使用者驚喜。當然,使用 InnoDB 儲存引擎肯定也有缺點。相對於其它儲存引擎來說,使用 InnoDB 儲存引擎的讀寫效率稍差,且佔用的資料空間相對較大。

物理儲存

使用 InnoDB 時,MySQL 會在資料目錄(Data)下建立一個名為 ibdata1 的 10MB 大小的自動擴充套件資料檔案,以及兩個名為 ib_logfile0 和 ib_logfile1 的 5MB 大小的紀錄檔檔案。

InnoDB 儲存引擎和 MyISAM 不太一樣,雖然也有 .frm 檔案來存放表結構定義相關的後設資料,但是表資料和索引資料是存放在一起的。至於是每個表單獨存放還是所有表存放在一起,使用者可以自己設定(下面會介紹如何設定)。

InnoDB 的物理儲存結構分為兩大部分:

1. 資料檔案(表資料和索引資料)

資料檔案用來存放資料表中的資料和所有的索引資料,包括主鍵和其他普通索引。

InnoDB 儲存的資料採用表空間(Tablepace)進行存放設計。表空間是用來存放 MySQL 系統相關資訊的一個特殊共用表空間。

InnoDB 的表空間分為以下兩種形式:
  1. 共用表空間,表資料和索引都存放在同一個表空間。預設的表空間檔案就是上面所提到的 MySQL 初始化路徑下的 ibdata1 檔案。
  2. 獨立表空間,每個表的資料和索引被存放在一個單獨的 .ibd 檔案中。

可以通過以下命令檢視 MySQL 是否使用獨立表空間:
mysql> SHOW VARIABLES LIKE 'innodb_file_per_table%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set, 1 warning (0.01 sec)
innodb_file_per_table 值為 ON 時表示開啟獨立表檔案,InnoDB 表的資料和索引都會以單獨的形式存放;值為 OFF 時,InnoDB 表的資料和索引都存放在一個表空間。可以通過設定該引數的值來決定是否使用獨立表空間,具體設定文章後面會講解。

1)共用表空間

共用表空間的資料檔案可以設定為固定大小和可自動擴充套件大小兩種形式。自動擴充套件形式的檔案可以設定檔案的最大大小和每次擴充套件量。在建立自動擴充套件的資料檔案時,建議大家最好加上最大尺寸的屬性,一個原因是檔案系統本身有一定的大小限制,還有一個原因就是方便自身維護。

當表空間快要用完的時候,我們必須要為其增加資料檔案,當然,只有共用表空間有此操作。

共用表空間增加資料檔案的操作比較簡單,只需要在 innodb_data_file_path 引數後面按照標準格式設定好檔案路徑和相關屬性即可。

innodb_data_file_path 引數負責定義共用表空間的路徑、初始化大小、自動擴充套件策略。可以使用以下命令檢視當前共用表空間檔案的路徑、大小和自動化策略:
mysql> SHOW VARIABLES LIKE 'innodb_data_file_path%';
+-----------------------+------------------------+
| Variable_name         | Value                  |
+-----------------------+------------------------+
| innodb_data_file_path | ibdata1:12M:autoextend |
+-----------------------+------------------------+
1 row in set, 1 warning (0.01 sec)
使用者可以通過 innodb_data_file_path 引數來指定表空間檔案,格式如下:

innodb_data_file_path=datafile_spec1[;datafile_spec2]...

其中,datafile_spec1 格式為表空間檔案路徑:大小:屬性,還可以指定多個檔案組成一個表空間,同時指定檔案的屬性,例如:

[mysqld]
innodb_data_file_path=/db/ibdata1:2000M;/dr2/db/ibdata2:2000M:autoextend

這裡將 /db/ibdata1 和 /dr2/db/ibdata2 兩個檔案用來組成表空間。若這兩個檔案位於不同的磁碟上,磁碟的負載可能被平均,因此可以提高資料庫的整體效能。

指定多個檔案時,autoextend 屬性只在最後一個資料檔案中指定,表示表空間自動擴充套件。這裡表示檔案 ibdata1 的大小為 2000MB,檔案 ibdata2 的大小為 2000MB,如果用完了 2000MB,該檔案還可以自動增長。

設定完 innodb_data_file_path 引數後,所有基於 InnoDB 儲存引擎的表的資料都會記錄到該共用表空間中。

不過這裡需要注意的是,InnoDB 在建立新資料檔案時不會建立目錄,如果指定目錄不存在,則會報錯並無法啟動。另外,InnoDB 給共用表空間增加資料檔案之後,必須要重新啟動資料庫系統才能生效。

這也是大多數人一直不太喜歡使用共用表空間而選用獨立表空間的原因之一。

2)獨立表空間

通過設定 innodb_file_per_table 引數,可以將每個基於 InnoDB 儲存引擎的表產生一個獨立表空間。

獨立表空間的命名規則為表名.ibd。通過這樣的方式,使用者不用將所有資料都存放於預設的表空間中。

使用 SET 命令開啟/關閉獨立表空間,命令和執行結果如下:
mysql> SET GLOBAL innodb_file_per_table=1;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW VARIABLES LIKE 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set, 1 warning (0.03 sec)

mysql> SET GLOBAL innodb_file_per_table=0;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES LIKE 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | OFF   |
+-----------------------+-------+
1 row in set, 1 warning (0.00 sec)
需要注意的是,單獨的表空間檔案只儲存該表的資料、索引和緩衝等資訊。所以無論是使用共用表空間還是獨享表空間來存放表,共用表空間都是必須存在的。

2. 紀錄檔檔案

預設情況下,InnoDB 儲存引擎的資料目錄下會有兩個名為 ib_logfile0 和 ib_logfile1 的檔案。在 MySQL 官方手冊中將其稱為 InnoDB 儲存引擎的重做紀錄檔檔案(redo log file)

重做紀錄檔檔案對 InnoDB 儲存引擎至關重要。InnoDB 可以通過重做紀錄檔將資料庫宕機時已經完成但還沒有來得及將資料寫入磁碟的事務恢復,也能將所有部分完成並已經寫入磁碟的未完成事務回滾,並且將資料還原,以此來保證資料的完整性。

每個 InnoDB 儲存引擎至少有 1 個重做紀錄檔檔案組(group),每個檔案組下至少有 2 個重做紀錄檔檔案,如預設的 ib_logfile0 和 ib_logfile1。

如果你的資料庫中有 InnoDB 的表,那麼千萬別全部刪除 InnoDB 的紀錄檔檔案,這很可能會讓你的資料庫 Crash,無法啟動,或者丟失資料。

資料庫不工作或停止響應、進程中斷等情況,在業界也叫做資料庫 Crash。

在 MySQL 啟動引數檔案設定中,InnoDB 的所有引數基本上都帶有字首“innodb_”,不論是 InnoDB 資料還是和紀錄檔相關,或者是其他一些效能,事務等等相關的引數都是一樣。

下面是影響重做紀錄檔檔案的引數:
  • innodb_log_file_size:指定每個重做紀錄檔的大小。
  • innodb_log_files_in_group:指定紀錄檔檔案組中重做紀錄檔檔案的數量,預設為 1。
  • innodb_mirrored_log_groups:指定紀錄檔映象檔案組的數量,預設為 1。
  • innodb_log_group_home_dir:指定紀錄檔檔案組所在路徑,預設為 ./

簡而言之,MySQL 中所有和 InnoDB 相關的系統變數都以“innodb_”做為字首。

拓展

在 MySQL 中,可以通過 skip-innodb 引數來遮蔽 InnoDB 儲存引擎,這樣即使我們在安裝編譯時,安裝了 InnoDB 儲存引擎,使用者也無法建立 InnoDB 的表。