您好,登錄后才能下訂單哦!
這篇文章主要講解了“InnoDB的外存數據結構介紹”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“InnoDB的外存數據結構介紹”吧!
“Everything is a file…”這句至理名言告訴我們一切都得從文件說起。那么對 InnoDB 外存數據結構的學習,我們也先從表和文件開始。
當我們使用 CREATE TABLE 創建一個表時,MySQL 會創建一個 .frm 文件和一個 .ibd 文件。.frm 文件是描述表結構定義的文件,而 .ibd 文件是 InnoDB 引擎層特有的,用于記錄InnoDB表的數據。舉個例子,在 db.CCCtest 下創建一個表”jersey_test”,建表語句如下:
CREATE TABLE `jersey_test` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `requestId` char(64) NOT NULL COMMENT 'request', `type` smallint(6) NOT NULL DEFAULT '0' COMMENT '類型', `name` varchar(64) NOT NULL COMMENT 'name', PRIMARY KEY (`id`), KEY `request` (`requestId`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
同時,我們往表中插入一條記錄如下:
[ jersey_test 表中的數據 ]
我們進入到 MySQL 的 /data 目錄下面,可以看到”jersey_test.frm”文件和”jersey_test.ibd”文件。
[ CCCtest 庫中的文件 ]
.frm 文件是二進制格式的,我們通過 hexdump 工具稍加分析,可以看到文件中除了一些編碼信息外,主要內容就是表結構信息。
[ .frm 文件內容 ]
這和我們使用 DESC TABLE 語法看到的表結構描述一致。
[ 表結構描述 ]
數據文件 .ibd 的分析與之類似。
InnoDB 中的表都是分文件存儲的,表中的行數據也按照相應的格式記錄在文件中。這里我們簡要歸納一下 InnoDB 所支持的文件存儲格式和行存儲格式。InnoDB 的文件格式由參數 innodb_file_format 指定,它支持 Antelope 和 Barracuda 兩種文件格式。Barracuda 是新的文件格式,它是包含 Antelope 格式在內的。Antelope 文件格式支持兩種行存儲格式,Compact 和 Redundant ,Barracuda 支持的新的行存儲格式為 Compressed 和 Dynamic。
[ InnoDB行存儲格式 ]
InnoDB 表的行存儲格式由參數 innodb_default_row_format 指定,在 5.7 版本中的默認值為 Dynamic 。行存儲格式決定了表中的記錄在文件中是如何進行存儲的,不同的行存儲格式有其特殊的優勢和劣勢,也會影響數據庫的行為。例如,使用 Compressed 這種格式可以使行記錄有更高的壓縮比,如果一個物理頁能存放的行記錄越多,它的索引或記錄查找會更快,內存消耗也會更小,但是壓縮數據本身也會帶回額外的系統開銷。另外一個需要注意的地方是,在進行數據庫表遷移時,需要關注源實例和目標實例的 Row Format 是否匹配。比如你有一個 MyISAM 的表要遷移到 InnoDB 上,并且 MyISAM 表的 Row Format 為默認值 Fixed ,此時需要改成 Dynamic ,因為這兩種格式對變長字段如 varchar/blob/text 等的處理是不一致的。
我們前面談到,InnoDB 每個表都有自己獨立的文件,其實是用到了它的默認行為,即使用獨立表空間,它由參數 innodb_file_per_table 控制。事實上 InnoDB 包含多種表空間類型,包括系統表空間 ( System TableSpace ),獨立表空間 ( File-Per-Table TableSpace ) 和通用表空間 ( General TableSpace ) 等。
系統表空間存儲了 InnoDB 的數據字典(元數據信息),系統表,雙寫緩沖區 ( doublewrite buffer ),Change Buffer 等。如果將參數 innodb_file_per_table 置為 OFF ,即所有的表數據都存儲在系統表空間中。但是在使用 InnoDB 時,更推薦的方法是將 innodb_file_per_table 置為 ON,即使用獨立表空間,它有如下幾個好處:
當使用 Truncate Table 和 Drop Table 命令刪除表時,系統會直接刪除表的數據文件,即回收物理空間。而使用系統表空間則無法回收這些物理空間;
和上面類似,當使用重建表的語法時,如 OPTIMIZE TABLE 或者 ALTER TABLE ENGINE = InnoDB 時,系統也能夠回收物理空間;
可以單獨將某個表指定到對應的存儲位置,這個存儲位置可以不在 MySQL 的數據目錄下。比如你想使用 RAID 或者 SSD 來存儲某個表,當你使用獨立表空間時,就可以通過 CREATE TABLE … DATA DIRECTORY 這個語法來實現。
使用獨立表空間也有一些潛在的問題。例如,每個表都有自己的單獨的文件,容易造成物理空間的浪費,如果數據庫有很多小表的話,這種空間浪費也會比較明顯。通用表空間 ( General TableSpace ) 可以緩解這個問題。通用表空間可以認為是 all-in-one (系統表空間) 和 file-per-table 的一個折中,它允許你使用 CREATE TABLESPACE 語法創建一個大的空間,然后你可以向這個空間中添加一些表的數據文件進行存儲,這些表的數據文件是共享存儲空間的。
索引可以說是 InnoDB 最重要的數據結構,介紹數據庫索引的資料也很多,談點題外話,什么是索引呢?索引其實就是幫助我們快速查找到數據( data ) 的輔助結構,可以說有數據的地方就需要索引。比如在文件系統里,數據的索引保存在元數據 inode 信息中,它記錄著這個文件所有的數據頁( data pages ) 具體在哪個位置,比如文件有10個頁,它就對應記錄10個頁框的物理地址。文件系統的索引當然也會有直接索引和間接索引,因為如果直接索引裝不下,就會用二級索引來裝,其結構如下圖所示,
[ 文件系統 inode 結構 ]
操作系統中最常見(也可能是最快)的索引大概是虛擬地址到物理地址的映射表。之所以快,首先在于它是連續的,當你進行跨頁訪問的時候不需要去計算下一個頁的地址,另外地址的轉換是由專門的硬件MMU來做的,硬件肯定更快。可以設想一下,如果文件存儲或者數據庫存儲的索引也采用虛擬地址映射表加上硬件加速的話,肯定會比現有的方式更快。虛擬地址直接映射到進程地址空間還可以減少進入內核態的開銷。
說回 InnoDB 的索引結構,InnoDB 的索引采用 B+ 樹這種數據結構,InnoDB 表中的行數據都是由聚簇索引 ( clustered index ) 組織的,它也被稱作主鍵索引 ( primar key ),即主鍵索引這棵 B+ 樹的葉子節點存儲的是主鍵對應的整行數據。為 InnoDB 的每個表都建立自增的主鍵索引非常重要,之所以需要自增,是因為在插入新記錄時可以做到連續,追加插入,這樣可以減少索引查找和索引頁分裂所帶來的額外開銷。InnoDB 其他的索引稱為二級索引 ( secondary index ),二級索引的葉子節點存儲的是主鍵索引的值,因此,絕大多數使用二級索引查詢記錄時,都會先通過二級索引找到主鍵索引的值,再通過主鍵索引找到行記錄。
在 InnoDB 中,數據一致性由 Redo Log 來保證,它使用的是 WAL(Write-Ahead Logging) 機制,即先寫日志再寫數據。InnoDB 使用這種方式在進行故障恢復時,會將 Redo Log 中的日志重做一遍,也就是將系統中未提交的事務重新執行。默認情況下,Redo Log 記錄在磁盤的 ib_logfile0 和 ib_logfile1 這兩個文件里,MySQL 循環的寫這兩個文件,因此,Redo Log 會有寫滿的情況,這里就需要介紹日志中的 checkpoint 機制。checkpoint 記錄了整個系統當前日志已經同步到的位置,也就是說,在 checkpoint 之前的事務都是已經提交的事務,數據不會存在不一致的情況。而當 MySQL 寫入 Redo Log 記錄追上 checkpoint 時,Redo Log 就寫滿了,此時需要等待 Redo Log 同步數據并釋放空間。
另一方面,在數據庫這種存儲系統中,更新操作失敗并回滾的情況是很常見的,所以需要特別關注這種情況,Undo Log 就是用來解決這個問題。Undo Log 記錄的是當一個更新操作失敗需要回滾時,應該進行哪些反向操作。即當你 insert 一條記錄時,Undo log中會記錄一條對應的 delete 記錄,反之亦然。
Redo Log 解決了本地數據(這里是指單點實例)一致性的問題。但是數據庫要做到高可用,還需要考慮多副本或跨區跨地域容災。MySQL Binlog 就提供了這種能力,Binlog 支持 Statement,Row 和 Mixed 三種模式。其中, Row 模式會記錄每行數據的修改操作,相比 Statement 模式,它能保證主從復制的正確性。
前面已經提到,Redo Log 和 Binlog 必須同時使用才能做到數據一致且高可用。接下來簡要分析一下數據庫進行插入或更新操作時是如何做到這一點的。MySQL 使用 WAL 機制進行更新操作,即先寫 Redo Log 和 Binlog,然后再寫數據。寫 Redo Log 和 Binlog 必須保證原子性,要么都更新成功,要么都更新失敗,否則會造成本地數據和其他副本數據不一致的情況。更新 Redo Log 和 Binlog 的過程稱為兩階段提交,其步驟為:
先將更新的操作寫到 Redo Log,此時流程標記為 prepare 狀態;
更新 Binlog,此時需將 BinLog 刷回磁盤才能視為成功;
提交事務(此時還會清除該事務 Undo 日志),流程標記為 commit 狀態。
兩階段提交可以保證數據的一致性,它在任何一個階段異常失敗都可以進行恢復。比如,如果事務已經是 commit 狀態,此時Redo Log 和 Binlog 都已更新成功;如果是在 prepare 狀態,此時就需要判斷 BinLog 中是否有完整的信息,如果有,則會進行 commit,如果沒有完整信息,則整個事務回滾。
感謝各位的閱讀,以上就是“InnoDB的外存數據結構介紹”的內容了,經過本文的學習后,相信大家對InnoDB的外存數據結構介紹這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。