1. 程式人生 > >InnoDB存儲引擎結構介紹

InnoDB存儲引擎結構介紹

sysbench 版本支持 也不會 功能 rep 增長 HERE 字節 隔離

Ⅰ、InnoDB發展史

時間 事件 備註
1995 由Heikki Tuuri創建Innobase Oy公司,開發InnoDB存儲引擎 Innobase開始做的是數據庫,希望賣掉該公司
1996 MySQL 1.0 發布
2000 MySQL3.23版本發布
2001 InnoDB存儲引擎集成到MySQL數據庫 以插件方式集成
2006 Innobase被Oracle公司收購(InnoDB作為開源產品,性能和功能很強大) InnoDB在被收購後的,MySQL中的InnoDB版本沒有改變
2010 MySQL5.5版本InnoDB存儲引擎稱為默認存儲引擎 MySQL被Sun收購,Sun被Oracle收購,使得MySQL和InnoDB重新在一起配合開發
至今 其他存儲引擎已經不再得到Oracle官方的後續開發

Ⅱ、InnoDB重要特性一覽

  • Fully ACID(InnoDB默認的Repeat Read隔離級別就支持)
  • Row-level Locking(支持行鎖)
  • Multi-version concurrency control(MVCC)(支持多版本並發控制)
  • Foreign key support(支持外鍵)
  • Automatic deadlock detection(死鎖自動檢測)
  • High performance、High scalability、High availability(高性能,高擴展,高可用)

Ⅲ、物理存儲結構

3.1 主要組成部分

表空間文件:

  • 獨立表空間
  • 共享表空間
  • undo表空間(MySQL5.6開始)

重做日誌文件:

  • 物理邏輯日誌
  • 沒有Oracle的歸檔重做日誌

3.2 細說表空間文件

表空間的概念:

  • 表空間是一個邏輯存儲的概念
  • 表空間可以由多個文件組成
  • 支持裸設備(可以直接使用O_DIRECT 方式繞過緩存,直接寫入磁盤)

表空間的分類:

①共享表空間(最早只有這個)

  • 存儲元數據信息
  • 存儲Change Buffer信息
  • 存儲Undo信息
  • MySQL4.0之前所有數據都是存儲在共享表空間中

②獨立表空間

  • MySQL4.0開始,支持每張表對應一個獨立表空間(ibd文件)
  • innodb-file-per-table=1(默認為1,這個參數關掉創建表,會發現對應的庫下面沒有該表的idb文件)
  • 分區表可以對應多個ibd文件

③undo表空間

  • MySQL5.6版本支持獨立的Undo表空間,默認是0,即undo記錄在共享表空間中
  • innodb_undo_tablespaces(該值8.0開始將會被剔除,不可修改,默認寫死,為2)

④臨時表空間

  • MySQL5.7增加了臨時表空間(ibtmp1)
  • innodb_temp_data_file_path

3.3 看下數據目錄

[root@VM_0_5_centos data3306]# ll ib*
-rw-r----- 1 mysql mysql    16285 Feb  4 18:15 ib_buffer_pool
-rw-r----- 1 mysql mysql 79691776 Feb 24 10:53 ibdata1          #共享表空間
-rw-r----- 1 mysql mysql 50331648 Feb 24 10:53 ib_logfile0      #重做日誌
-rw-r----- 1 mysql mysql 50331648 Feb  4 15:06 ib_logfile1
-rw-r----- 1 mysql mysql 12582912 Feb 24 10:14 ibtmp1           #臨時表空間

兩個ib_logfile是循環交替寫入的,SSD下盡可能設大,單個文件4G/8G,設置太小可能會導致臟頁刷新時hang住

MySQL中現在只有這兩個文件不會歸檔,最老的3.23版本支持歸檔,因為MySQL有二進制日誌所以把這個功能閹割了

[root@VM_0_5_centos data3306]# cd test
[root@VM_0_5_centos test]# ll
total 228
-rw-r----- 1 mysql mysql       65 Feb  4 13:21 db.opt           #記錄默認字符集和字符集排序規則
-rw-r----- 1 mysql mysql  8554 Feb  1 15:45 abc.frm             #表結構文件
-rw-r----- 1 mysql mysql 98304 Feb 24 10:53 abc.ibd             #獨立表空間

就性能而言,獨立和共享速度是一樣的,基本上區別

雖然ibadta1是一個文件,但是在底層申請也是1兆1兆地申請的空間,是連續的(兩種都是以區的方式來管理),在磁盤上的表現是一樣的,1M的數據基本上可以認為是連續的

tips:

sysbench去測8個文件開16個線程和測1個文件開128個線程,測出來iops是一樣的,因為它的分配和管理機制都是一樣的

那為什麽MySQL4.0版本開始引入了獨立表空間呢?

主要是為了管理方便,表現為:

  • 看上去清晰
  • 刪除文件非常簡單,drop完空間可釋放,對於ibdata1來說,一個文件,只能增不能減,刪除一張表只是把這張表對應的空間標為可用,但是空間並不能回收
    刪除.ibd文件是不行的,因為對應的innodb元數據表裏面的數據沒有刪

.ibd和.ibdata1文件壞了修復的話收費是按行數來算的很貴的哦,相對而言ibdata1文件修復難度更大

切記:不要在數據目錄下刪除任何文件

3.4 小常識

單個ibd文件直接拷貝到新的數據庫中無法直接恢復:

  • 原因一:元數據信息還是在ibdata1中
  • 原因二:部分索引文件存在於Change Buffer中,目前還是存放於ibdata1文件中

查看表空間的元數據信息

select * from information_schema.innodb_sys_tablespaces;

Ⅳ、邏輯存儲結構

4.1 從上到下的結構

表空間
內部有多個段對象(Segment)組成
每個段(Segment)由區(Extent)組成
每個區(Extent)由頁(Page)組成
每個頁裏面保存數據(或者叫記錄Row)

段:

段對用戶來說是透明的,也是一個邏輯的概念,用來組織管理區

在MySQL系統表中是看不到段這個元數據的,但是邏輯上的確存在(重點理解區和頁)

區:

區包含頁

區是最小的空間申請單位,表空間文件要擴展是以區的單位來擴展

區的大小固定為1M,這1M在物理上是連續的,但1M和1M之間不保證連續

page_size=16K 就是1M * 1024 / 16 = 64個頁

16k 64個頁
8k 128個頁
4k 256個頁

通常一次申請4個區大小,1兆1兆地申請,特殊情況會申請5個區,很少發生這種情況

頁 :

等價於ORACLE中的塊 ,最小的I/O操作單位

tips:

data的最小單位不是頁,而是頁中的記錄(row)

普通用戶表中MySQL默認的每個頁為16K

  • 從MySQL 5.6開始使用 innodb_page_size可以控制頁大小
  • 一旦數據庫通過innodb_page_size創建完成,則後續無法更改
  • innodb_page_size 是針對普通表的,壓縮表不受其限制

4.2 來來來,吹兩手

從5.6開始可以調整大小,但只能設置4k和8k,從5.7開始還可以設置32k,64k,如果設置為32k或者64k那區的大小就變為2M和4M

什麽淘寶標準MySQL配置參數把這個大小設置為4k,完全扯淡,就算在ssd下4k可能也不會比16k好,另外設置為4k,io操作會變多,不要迷信,現在的表偏向於寬表(很多列組成,單行記錄比較大),一行超過1k甚至4k以上,這時候這個頁大小設為4,性能會很差。

設置小了,B+ tree高度變高,io變多,性能變差;如果是寬列,4k的頁會導致行外存,效率變差

目前為止,大家都用的SSD,列比較寬,內存也比較大,就保留16k或者嘗試一下32k(一些單列特別大的場景,大頁性能有優勢)

tips:

MySQL頁大小和ORACLE頁大小不同的是,MySQL頁大小是全局的,一旦初始化好,就不可再修改,不像ORACLE可以設置每張表的頁大小

Ⅴ、MySQL中如何定位到一個頁

SpaceID

  • 每個表空間都對應一個SpaceID,而表空間又對應一個ibd文件,那麽一個ibd文件也對應一個SpaceID
  • ibdata1對應的SpaceID為0,每創建一個表空間(ibd文件),SpaceID自增長(全局)

PageNumber

  • 在一個表空間中,第幾個16K的頁(假設 innodb_page_size = 16K)即為PageNumber

技術分享圖片

  • 每次讀取Page時,都是通過SpaceID和PageNumber進行讀取
  • 可以簡單理解為從表空間的開頭讀多少個PageNumber * PageSize的字節(偏移)
  • 想成數組,數組的名字就是SpaceID,數組的下標就是PageNumber
  • 在一個SpaceID(ibd文件)中,PageNumber是唯一且自增的
  • 刪除表的時候,SpaceID不會回收 ,SpaceID是全局自增長的

tips:

這裏的區(extent)的概念已經弱化

在這個例子中,第一個區的PageNumber是(0到63)且這64個頁在物理上是連續的;第二個區的PageNumber是(64到127) 且這64個頁在物理上也是連的

但是(0到63)和(64到127)之間在物理上則不一定是連續的,因為區和區之間在物理上不一定是連續的

隨便看看

(root@localhost) [information_schema]> select space, name from information_schema.innodb_sys_tablespaces order by space limit 5;
+-------+---------------------+
| space | name                |
+-------+---------------------+
|     2 | mysql/plugin        |
|     3 | mysql/servers       |
|     4 | mysql/help_topic    |
|     5 | mysql/help_category |
|     6 | mysql/help_relation |
+-------+---------------------+
5 rows in set (0.00 sec)

(root@localhost) [information_schema]> select name, space, table_id from information_schema.innodb_sys_tables where space=0;
+------------------+-------+----------+
| name             | space | table_id |
+------------------+-------+----------+
| SYS_DATAFILES    |     0 |       14 |
| SYS_FOREIGN      |     0 |       11 |
| SYS_FOREIGN_COLS |     0 |       12 |
| SYS_TABLESPACES  |     0 |       13 |
| SYS_VIRTUAL      |     0 |       15 |
+------------------+-------+----------+
5 rows in set (0.00 sec)

(root@localhost) [information_schema]> select name, space, table_id from information_schema.innodb_sys_tables where space<>0 order by space limit 5;
+---------------------+-------+----------+
| name                | space | table_id |
+---------------------+-------+----------+
| mysql/plugin        |     2 |       16 |
| mysql/servers       |     3 |       17 |
| mysql/help_topic    |     4 |       35 |
| mysql/help_category |     5 |       36 |
| mysql/help_relation |     6 |       38 |
+---------------------+-------+----------+
5 rows in set (0.00 sec)
  • 獨立表空間的table_id和SpaceID一一對應
  • 共享表空間是多個table_id對應一個SpaceID
  • SpaceID為0的是ibdata1,1這個位置沒有,空的

InnoDB存儲引擎結構介紹