溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹

發(fā)布時間:2021-09-09 07:12:01 來源:億速云 閱讀:125 作者:chen 欄目:MySQL數(shù)據(jù)庫

這篇文章主要講解了“InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹”吧!

PartⅠ 表和表空間

“Everything is a file…”這句至理名言告訴我們一切都得從文件說起。那么對 InnoDB 外存數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí),我們也先從表和文件開始。

一、表 ( Table )

當(dāng)我們使用 CREATE TABLE 創(chuàng)建一個表時,MySQL 會創(chuàng)建一個 .frm 文件和一個 .ibd 文件。.frm 文件是描述表結(jié)構(gòu)定義的文件,而 .ibd 文件是 InnoDB 引擎層特有的,用于記錄InnoDB表的數(shù)據(jù)。舉個例子,在 db.CCCtest 下創(chuàng)建一個表”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

同時,我們往表中插入一條記錄如下:

InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹

[ jersey_test 表中的數(shù)據(jù) ]

我們進(jìn)入到 MySQL 的 /data 目錄下面,可以看到”jersey_test.frm”文件和”jersey_test.ibd”文件。

InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹[ CCCtest 庫中的文件 ]

.frm 文件是二進(jìn)制格式的,我們通過 hexdump 工具稍加分析,可以看到文件中除了一些編碼信息外,主要內(nèi)容就是表結(jié)構(gòu)信息。

InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹[ .frm 文件內(nèi)容 ]

這和我們使用 DESC TABLE 語法看到的表結(jié)構(gòu)描述一致。

InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹[ 表結(jié)構(gòu)描述 ]

數(shù)據(jù)文件 .ibd 的分析與之類似。

二、Row Formats

InnoDB 中的表都是分文件存儲的,表中的行數(shù)據(jù)也按照相應(yīng)的格式記錄在文件中。這里我們簡要?dú)w納一下 InnoDB 所支持的文件存儲格式和行存儲格式。InnoDB 的文件格式由參數(shù) innodb_file_format 指定,它支持 Antelope 和 Barracuda 兩種文件格式。Barracuda 是新的文件格式,它是包含 Antelope 格式在內(nèi)的。Antelope 文件格式支持兩種行存儲格式,Compact 和 Redundant ,Barracuda 支持的新的行存儲格式為 Compressed 和 Dynamic。

InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹[ InnoDB行存儲格式 ]

InnoDB 表的行存儲格式由參數(shù) innodb_default_row_format 指定,在 5.7 版本中的默認(rèn)值為 Dynamic 。行存儲格式?jīng)Q定了表中的記錄在文件中是如何進(jìn)行存儲的,不同的行存儲格式有其特殊的優(yōu)勢和劣勢,也會影響數(shù)據(jù)庫的行為。例如,使用 Compressed 這種格式可以使行記錄有更高的壓縮比,如果一個物理頁能存放的行記錄越多,它的索引或記錄查找會更快,內(nèi)存消耗也會更小,但是壓縮數(shù)據(jù)本身也會帶回額外的系統(tǒng)開銷。另外一個需要注意的地方是,在進(jìn)行數(shù)據(jù)庫表遷移時,需要關(guān)注源實(shí)例和目標(biāo)實(shí)例的 Row Format 是否匹配。比如你有一個 MyISAM 的表要遷移到 InnoDB 上,并且 MyISAM 表的 Row Format 為默認(rèn)值 Fixed ,此時需要改成 Dynamic ,因?yàn)檫@兩種格式對變長字段如 varchar/blob/text 等的處理是不一致的。

三、表空間 ( TableSpace )

我們前面談到,InnoDB 每個表都有自己獨(dú)立的文件,其實(shí)是用到了它的默認(rèn)行為,即使用獨(dú)立表空間,它由參數(shù) innodb_file_per_table 控制。事實(shí)上 InnoDB 包含多種表空間類型,包括系統(tǒng)表空間 ( System TableSpace ),獨(dú)立表空間 ( File-Per-Table TableSpace ) 和通用表空間 ( General TableSpace ) 等。

系統(tǒng)表空間存儲了 InnoDB 的數(shù)據(jù)字典(元數(shù)據(jù)信息),系統(tǒng)表,雙寫緩沖區(qū) ( doublewrite buffer ),Change Buffer 等。如果將參數(shù) innodb_file_per_table 置為 OFF ,即所有的表數(shù)據(jù)都存儲在系統(tǒng)表空間中。但是在使用 InnoDB 時,更推薦的方法是將 innodb_file_per_table 置為 ON,即使用獨(dú)立表空間,它有如下幾個好處:

  1. 當(dāng)使用 Truncate Table 和 Drop Table 命令刪除表時,系統(tǒng)會直接刪除表的數(shù)據(jù)文件,即回收物理空間。而使用系統(tǒng)表空間則無法回收這些物理空間;

  2. 和上面類似,當(dāng)使用重建表的語法時,如 OPTIMIZE TABLE 或者 ALTER TABLE ENGINE = InnoDB 時,系統(tǒng)也能夠回收物理空間;

  3. 可以單獨(dú)將某個表指定到對應(yīng)的存儲位置,這個存儲位置可以不在 MySQL 的數(shù)據(jù)目錄下。比如你想使用 RAID 或者 SSD 來存儲某個表,當(dāng)你使用獨(dú)立表空間時,就可以通過 CREATE TABLE … DATA DIRECTORY 這個語法來實(shí)現(xiàn)。

使用獨(dú)立表空間也有一些潛在的問題。例如,每個表都有自己的單獨(dú)的文件,容易造成物理空間的浪費(fèi),如果數(shù)據(jù)庫有很多小表的話,這種空間浪費(fèi)也會比較明顯。通用表空間 ( General TableSpace ) 可以緩解這個問題。通用表空間可以認(rèn)為是 all-in-one (系統(tǒng)表空間) 和 file-per-table 的一個折中,它允許你使用 CREATE TABLESPACE 語法創(chuàng)建一個大的空間,然后你可以向這個空間中添加一些表的數(shù)據(jù)文件進(jìn)行存儲,這些表的數(shù)據(jù)文件是共享存儲空間的。

Part Ⅱ 索引

索引可以說是 InnoDB 最重要的數(shù)據(jù)結(jié)構(gòu),介紹數(shù)據(jù)庫索引的資料也很多,談點(diǎn)題外話,什么是索引呢?索引其實(shí)就是幫助我們快速查找到數(shù)據(jù)( data ) 的輔助結(jié)構(gòu),可以說有數(shù)據(jù)的地方就需要索引。比如在文件系統(tǒng)里,數(shù)據(jù)的索引保存在元數(shù)據(jù) inode 信息中,它記錄著這個文件所有的數(shù)據(jù)頁( data pages ) 具體在哪個位置,比如文件有10個頁,它就對應(yīng)記錄10個頁框的物理地址。文件系統(tǒng)的索引當(dāng)然也會有直接索引和間接索引,因?yàn)槿绻苯铀饕b不下,就會用二級索引來裝,其結(jié)構(gòu)如下圖所示,

InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹[ 文件系統(tǒng) inode 結(jié)構(gòu) ]

操作系統(tǒng)中最常見(也可能是最快)的索引大概是虛擬地址到物理地址的映射表。之所以快,首先在于它是連續(xù)的,當(dāng)你進(jìn)行跨頁訪問的時候不需要去計算下一個頁的地址,另外地址的轉(zhuǎn)換是由專門的硬件MMU來做的,硬件肯定更快??梢栽O(shè)想一下,如果文件存儲或者數(shù)據(jù)庫存儲的索引也采用虛擬地址映射表加上硬件加速的話,肯定會比現(xiàn)有的方式更快。虛擬地址直接映射到進(jìn)程地址空間還可以減少進(jìn)入內(nèi)核態(tài)的開銷。

說回 InnoDB 的索引結(jié)構(gòu),InnoDB 的索引采用 B+ 樹這種數(shù)據(jù)結(jié)構(gòu),InnoDB 表中的行數(shù)據(jù)都是由聚簇索引 ( clustered index ) 組織的,它也被稱作主鍵索引 ( primar key ),即主鍵索引這棵 B+ 樹的葉子節(jié)點(diǎn)存儲的是主鍵對應(yīng)的整行數(shù)據(jù)。為 InnoDB 的每個表都建立自增的主鍵索引非常重要,之所以需要自增,是因?yàn)樵诓迦胄掠涗洉r可以做到連續(xù),追加插入,這樣可以減少索引查找和索引頁分裂所帶來的額外開銷。InnoDB 其他的索引稱為二級索引 ( secondary index ),二級索引的葉子節(jié)點(diǎn)存儲的是主鍵索引的值,因此,絕大多數(shù)使用二級索引查詢記錄時,都會先通過二級索引找到主鍵索引的值,再通過主鍵索引找到行記錄。

Part Ⅲ 恢復(fù)日志

一、重做日志和回滾日志 ( Redo Log & Undo Log )

在 InnoDB 中,數(shù)據(jù)一致性由 Redo Log 來保證,它使用的是 WAL(Write-Ahead Logging) 機(jī)制,即先寫日志再寫數(shù)據(jù)。InnoDB 使用這種方式在進(jìn)行故障恢復(fù)時,會將 Redo Log 中的日志重做一遍,也就是將系統(tǒng)中未提交的事務(wù)重新執(zhí)行。默認(rèn)情況下,Redo Log 記錄在磁盤的 ib_logfile0 和 ib_logfile1 這兩個文件里,MySQL 循環(huán)的寫這兩個文件,因此,Redo Log 會有寫滿的情況,這里就需要介紹日志中的 checkpoint 機(jī)制。checkpoint 記錄了整個系統(tǒng)當(dāng)前日志已經(jīng)同步到的位置,也就是說,在 checkpoint 之前的事務(wù)都是已經(jīng)提交的事務(wù),數(shù)據(jù)不會存在不一致的情況。而當(dāng) MySQL 寫入 Redo Log 記錄追上 checkpoint 時,Redo Log 就寫滿了,此時需要等待 Redo Log 同步數(shù)據(jù)并釋放空間。

另一方面,在數(shù)據(jù)庫這種存儲系統(tǒng)中,更新操作失敗并回滾的情況是很常見的,所以需要特別關(guān)注這種情況,Undo Log 就是用來解決這個問題。Undo Log 記錄的是當(dāng)一個更新操作失敗需要回滾時,應(yīng)該進(jìn)行哪些反向操作。即當(dāng)你 insert 一條記錄時,Undo log中會記錄一條對應(yīng)的 delete 記錄,反之亦然。

二、Binlog

Redo Log 解決了本地數(shù)據(jù)(這里是指單點(diǎn)實(shí)例)一致性的問題。但是數(shù)據(jù)庫要做到高可用,還需要考慮多副本或跨區(qū)跨地域容災(zāi)。MySQL Binlog 就提供了這種能力,Binlog 支持 Statement,Row 和 Mixed 三種模式。其中, Row 模式會記錄每行數(shù)據(jù)的修改操作,相比 Statement 模式,它能保證主從復(fù)制的正確性。

前面已經(jīng)提到,Redo Log 和 Binlog 必須同時使用才能做到數(shù)據(jù)一致且高可用。接下來簡要分析一下數(shù)據(jù)庫進(jìn)行插入或更新操作時是如何做到這一點(diǎn)的。MySQL 使用 WAL 機(jī)制進(jìn)行更新操作,即先寫 Redo Log 和 Binlog,然后再寫數(shù)據(jù)。寫 Redo Log 和 Binlog 必須保證原子性,要么都更新成功,要么都更新失敗,否則會造成本地數(shù)據(jù)和其他副本數(shù)據(jù)不一致的情況。更新 Redo Log 和 Binlog 的過程稱為兩階段提交,其步驟為:

  1. 先將更新的操作寫到 Redo Log,此時流程標(biāo)記為 prepare 狀態(tài);

  2. 更新 Binlog,此時需將 BinLog 刷回磁盤才能視為成功;

  3. 提交事務(wù)(此時還會清除該事務(wù) Undo 日志),流程標(biāo)記為 commit 狀態(tài)。

兩階段提交可以保證數(shù)據(jù)的一致性,它在任何一個階段異常失敗都可以進(jìn)行恢復(fù)。比如,如果事務(wù)已經(jīng)是 commit 狀態(tài),此時Redo Log 和 Binlog 都已更新成功;如果是在 prepare 狀態(tài),此時就需要判斷 BinLog 中是否有完整的信息,如果有,則會進(jìn)行 commit,如果沒有完整信息,則整個事務(wù)回滾。

感謝各位的閱讀,以上就是“InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對InnoDB的外存數(shù)據(jù)結(jié)構(gòu)介紹這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI