InnoDB磁盤數據結構

InnoDB磁盤數據結構主要包含:

  • Tables 表結構
  • Indexes 索引結構
  • Tablespaces 表空間
  • InnoDB Data Dictionary InnoDB數據字典
  • Doublewrite Buffer 雙寫緩存
  • Redo Log
  • Undo Logs

Tables

create table

CREATE TABLE t1 (a INT, b CHAR (20), PRIMARY KEY (a)) ENGINE=InnoDB;

k可以通過engine指定使用的引擎,也可以查看默認的數據庫引擎:

SELECT @@default_storage_engine;

一個InnoDB的表和他的索引可以創建在系統表空間、獨立表空間或者通用表空間。innodb_file_per_table默認開啓,標識每個表會創建獨立的表空間。關閉則會將數據放在系統表空間,我們也可以在建表時使用 CREATE TABLE … TABLESPACE 語句指定表空間。
當我們創建一個InnoDB表時,MySQL創建一個frm文件在數據庫目錄下。如果一個表在獨立表空間,那麼也會創建一個idb文件。如果一個表時系統表空間,則會出案件在一個存在的dibdata文件。如果是通用表空間,則會創建在一個存在的ibd文件。通用表空間可以創建在data目錄內或外部。

InnoDB Tables and .frm Files

MySQL存儲表字典信息在frm文件。

Indexes

聚集索引&二級索引

每一個InnoDB表都存在聚集索引,通常,聚集索引即爲主鍵:

  • 如果定義了主鍵,InnoDB通常使用主鍵用作聚集索引。如果沒有邏輯上唯一不爲空的列,那麼會增加一個新的自增列,用作聚集索引。
  • 如果沒有主鍵,那麼會使用第一個唯一索引用來作爲聚集索引
  • 如果沒有主鍵和唯一索引,那麼會默認創建一個隱藏的聚集索引,索引命名爲GEN_CLUST_INDEX。該索引在自動創建的一個列上,包含row ID。

聚集索引如何提高查詢速度

通過聚集索引查詢很快,是因爲索引直接包含所有數據的頁(真實情況實在葉子節點含有數據)。如果表很大,與使用索引記錄的不同頁存儲行數據的存儲組織相比,聚集索引體系結構通常會保存磁盤I/O操作。

二級索引如何關聯聚集索引

在InnoDB二級索引包含聚集索引,InnoDB使用主鍵值去搜索數據(即我們所說的回表操作)。

表空間

InnoDB數據字典

InnoDB數據字典由內部系統表組成,這些表包含用於跟蹤表、索引和表列等對象的元數據。元數據物理上位於InnoDB系統表空間中。由於歷史原因,數據字典元數據在一定程度上與InnoDB表元數據文件(.frm文件)中存儲的信息重疊。

Doublewrite Buffer

Doublewrite Buffer 是在系統表空間的一個存儲區域,當InnoDB從buffer pool刷新頁數據時,會將數據先寫入Doublewrite Buffer中。當MySQL在寫入page 出現系統故障時,InnoDB可以從 doublewrite buffer 獲取頁的的數據,從而實現故障恢復。
雖然數據總是寫入兩次,doublewrite buffer並不會消耗兩次IO,data會寫入一個連續的塊,然後使用fsync() 函數寫入系統。
Doublewrite Buffer大部分默認操作都是開啓的,可以通過innodb_doublewrite 參數關閉。

Redo Log

此節主要參考《MySQL技術內幕:InnoDB存儲引擎》第二版 7.2.1章節

基本概念

Redo Log是一個磁盤數據結構,在故障恢復中來修復未完成的事務數據,主要是完成事務ACID的D特性。在正常操作下, 重做日誌對由sql語句或者低級API產生的表數據表更數據進行編碼。在意外宕機而無法提交的數據會在初始化後或者重新連接後進行自動回滾。
默認的,redo log在物理文件上記錄在2個文件上,命名ib_logfile0 和 ib_logfile1,MySQL寫入redo log 文件通過循環方式。redo log的數據通過受影響的行數進行編碼,這些數據統稱爲重做。重做日誌的數據通過LSN值來標識。

Force Log at Commit

InnoDB通過Force Log at Commit來實現事務的持久性,即當事務提交時,必須先將事務的日誌寫入重做日誌文件中進行持久化。 在InnoDB中,重做日誌由redo log和undo log組成。
innodb_flush_log_at_trx_commit 來配置在什麼時候刷新log buffe到文件系統中,不同的配置對事務的一致性以及數據庫的性能影響各不同:

  1. 當設置爲1的時候,標識每次事務提交的時候都會將log buffer的日誌寫入緩存並刷新到文件中。這種方式,每次系統奔潰都不會丟失數據
  2. 當設置爲0的時候,事務提交時不會將log buffer中日誌寫入到os buffer,而是每秒寫入os buffer並調用fsync()寫入到磁盤文件中。也就是說設置爲0時是(大約)每秒刷新寫入到磁盤中的,當系統崩潰,會丟失1秒鐘的數據。
  3. 當設置爲2的時候,每次提交都僅寫入到os buffer,然後是每秒調用fsync()將os buffer中的日誌寫入到磁盤文件。

寫入時間

重做日誌與binlog不同,binlog是在事務提交完成後一次寫入,而redo log是在事務進行中不斷被寫入的,這種表現爲,如果存在多個事務併發執行,寫入的日誌文件不是連續的。

log block

在InnoDB中,重做日誌都是以512節存儲的,這意味着重做日誌緩存、重做日誌文件都是以block的方式保存,這種稱爲重做日誌塊 redo log block,每塊大小512字節。
若一個頁中產生的重做日誌大於512字節,那麼會分割爲多個重做日誌塊進行存儲。因爲重做日誌大小與扇區大小一致,所以重做日誌的寫入是原子性的,不需要double write。
重做日誌除了日誌本身外,還包含重做日誌頭(12字節)和日誌塊尾(8字節)兩部分。

log group

log group 重做日誌組,其中有多個重做日誌,但是實際mysql禁用此功能,一個重做日誌組目前只包含一個重組日誌文件。
log group是一個邏輯概念,並沒有一個實際的物理文件來標識重做日誌組。log gourp由多個重做日誌文件組成,每個重做日誌文件大小相同。重做日誌文件保存的就是之前log buffer中保存的的log block。在InnoDB運行過程中,log buffer根據一定的規則將內存中的log block刷新到磁盤,規則是:
-1. 事務提交時
-2. 當log buffer有一半的內存空間已經被使用時
-3. log checkpoint時
log block寫入logfile採用追加的形式,當一個log file被寫滿時,會寫入下一個redo log file,一直輪詢寫入。

重做日誌格式

不同的數據庫操作產生不同的重做日誌。此外,InnoDB的管理都是基於頁的,重做日誌格式也是基於頁的,雖然有着不同的重做日誌格式,但是有着通用的頭部格式。通用的頭部格式包含以下三部分:

  1. redo_log_type 重做日誌類型
  2. space:表空間id
  3. page_no:頁的偏移量

LSN

LSN是Log Sequence Number的縮寫,其代表的是日誌序列號。在InnoDB引擎中,LSN佔用8字節,並且單調遞增。LSN標識的含義有:

  1. 重做日誌的寫入總量:例如重做日誌爲1000,t1寫入100,則爲1100,t2寫入300,則爲1400
  2. checkpoint的位置
  3. 頁的版本
    show engine innodb status 可以查看對應的LSN
---
LOG
---
Log sequence number 47924638065
Log flushed up to   47924638065
Pages flushed up to 47924638065
Last checkpoint at  47924638065
0 pending log writes, 0 pending chkp writes
8 log i/o's done, 0.00 log i/o's/second

Log sequence number 標識當前LSN,Log flushed up標識刷新到重做日誌文件盤的LSN,Last checkpoint at 標識刷新到磁盤的LSN。

checkpoint

checkpoint標識已經刷新到磁盤的重做日誌,因此恢復數據庫的過程也只需要恢復checkpoint開始的日誌。例如LSN爲1300,checkpoint爲1000,那麼數據庫只需要恢復1000到1300之前的日誌即可。

Undo Log

undo log 是與單個讀寫事務關聯的回滾記錄的集合。undo log包含如何回滾一個事務對聚集索引更改的最新記錄。如果另一個事務需要一致性非鎖定讀取原始數據,則會嘗試從undo log讀取未修改的數據。undo log存在於undo segment,undo segment存在於 rollback segments。rollback segments存在於系統表空間、撤消表空間和臨時表空間中。
在事務回滾時,並不是把頁回滾到最初的狀態,而是執行與之前相反的操作。insert則執行delete,update則執行相反的update。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章