Innodb存儲表結(jié)構(gòu)

索引組織表(index organized table)

在InnoDB存儲引擎中,表都是根據(jù)主鍵順序組織存放的,這種存儲方式的表叫索引組織表酥泞。在InnoDB存在引擎表中,每張表都有個主鍵(Primary key)啃憎,如果在創(chuàng)建表時沒有顯示定義主鍵芝囤,則會按照如下方式選擇或者創(chuàng)建主鍵:

(1) 判定是否有非空的唯一索引(unique not null),如果有則該列即為主鍵辛萍。若果有多個悯姊,則選擇建表是第一個定義的非空位于索引為主鍵。注意:主鍵的選擇根據(jù)的是定義索引的順序贩毕,而不是建表時的列的順序悯许。

(2) 如果不存在唯一索引,InnoDB存儲引擎字段創(chuàng)建一個6字節(jié)大小的指針(僅內(nèi)部可見)辉阶。

InnoDB邏輯存儲結(jié)構(gòu)

在InnoDB存儲引擎中先壕,所有的數(shù)據(jù)都被邏輯地存放在一個空間中,稱之為表空間(tablespace)睛藻。表空間又由段(segment)启上、區(qū)(extent)、頁(page)組成店印。InnoDB存儲引擎的邏輯存儲結(jié)構(gòu)如下圖冈在。


表空間 可以看見InnoDB存儲引擎邏輯結(jié)構(gòu)的最高層,所有的數(shù)據(jù)都存放在表空間中按摘。表空間又分為獨立表空間和共享表空間包券。通過參數(shù)innodb_file_per_table參數(shù)來決定使用何種類型的表空間纫谅。但是需要注意的是獨立表空間內(nèi)只存放數(shù)據(jù)、索引和插入緩沖頁溅固,其他的數(shù)據(jù)付秕,如回滾(undo)信息、插入緩沖索引頁侍郭、系統(tǒng)事務(wù)信息询吴、二次寫緩沖(double write buffer)等還是放置在原來的共享表空間中。

表空間由各個段組成亮元。常見的段有數(shù)據(jù)段猛计、索引段、回滾段等爆捞。InnoDB存儲引擎是索引組織表奉瘤,因此數(shù)據(jù)即索引,索引即數(shù)據(jù)煮甥。數(shù)據(jù)段即為B+樹的葉子點(leaf node segment)盗温,索引段為B+數(shù)據(jù)的非索引節(jié)點(non-leaf node segment)〕芍猓回滾段比較特殊以后在介紹卖局。段都是引擎自身管理的。

區(qū) 區(qū)是由連續(xù)頁組成的空間艇劫。InnoDB存儲引擎頁的大小為16KB吼驶,一個區(qū)有64個連續(xù)的頁組成,所以每個區(qū)的大小都是1MB店煞。參數(shù)innodb_page_size可設(shè)置頁的大小4K、8K风钻,但是顷蟀,不論頁的大小怎么變化,區(qū)的大小不變1M骡技。但是有這樣一個問題:在開啟獨立表空間之后鸣个,創(chuàng)建的表默認(rèn)大小是96K,區(qū)中是64個連續(xù)的頁布朦,創(chuàng)建的表空間應(yīng)該是1M才對呀囤萤?這是因為在每個段的開始時,先用32個頁大小的碎片頁(fragment page)來保存數(shù)據(jù)是趴,在使用完這些頁之后才是64個連續(xù)的頁的申請涛舍。這樣做是對于一些小表或者undo這類的段,可以在開始時申請較少的空間唆途,節(jié)省磁盤容量的開銷富雅。

頁是InnoDB磁盤管理的最小單位掸驱。默認(rèn)大小為16K,可以通過innodb_page_size將頁的大小設(shè)置為4K没佑、8K毕贼、16K,則所有表中頁的大小都為設(shè)置值蛤奢,不可以對其再次修改鬼癣。除非通過mysqldump導(dǎo)入和導(dǎo)出操作來產(chǎn)生新的庫。常見的頁的類型有:數(shù)據(jù)頁(B-tree Node)啤贩、undo頁(unod Log Page)待秃、系統(tǒng)頁(System Page)、事務(wù)數(shù)據(jù)頁(Transaction system Page)瓜晤、插入緩沖空閑列表頁(Insert Buffer Free List)锥余、未壓縮的二進制大對象頁(Uncompressed BLOB Page)、壓縮的二進制對象頁(compressed BLOB Page)痢掠。

InnoDB存儲引擎是面向行的(row-oriented)驱犹,也就是說數(shù)據(jù)是按行進行存放的。每個頁存放的行記錄也是有硬性定義的足画,最多運行存放(16K/2-200)行的記錄雄驹,即7992行記錄。

InnoDB物理存儲結(jié)構(gòu)

InnoDB表由共享表空間(ibdata1)淹辞,redo日志文件組(ib_logfile0医舆,ib_logfile1),表結(jié)構(gòu)定義文件(表名.frm)組成象缀。當(dāng)開啟獨立表空間時蔬将,還有以表名.ibd的文件,存儲數(shù)據(jù)央星,索引霞怀,插入緩存列。

InnoDB行記錄格式

InnoDB存儲引擎的記錄是以行的形式存儲的莉给,這就表明頁中保存著表中一行行的數(shù)據(jù)毙石。其類型有REDUNDANT、 COMPACT颓遏、COMPRESS徐矩、DYNAMIC四種∪保可以通過show table status滤灯。

COMPACT 在MySQL 5.0中引入,其設(shè)計目標(biāo)是高效的存儲數(shù)據(jù)。也就是一個頁中存放的行數(shù)據(jù)越多力喷,其性能越高刽漂。compact行記錄的存放方式:

  1. 第一部分是一個非NULL變長字段長度列表(字節(jié)數(shù)與非NULL變長字段數(shù)相同),且其是按列的順序逆序放置的弟孟。

  2. 第二部分是NULL標(biāo)志位(1個bit表示對應(yīng)列的NULL)贝咙,該位指示了改行數(shù)據(jù)中是否有NULL值。

  3. 第三部分是記錄頭信息拂募,固定占用5字節(jié)(40位)庭猩,每位含義如下:

    最后的部分就是實際存儲每列的數(shù)據(jù)。

  • 需要注意的是:
  1. NULL除了占有NULL標(biāo)志位陈症,實際存儲不占任何空間蔼水。
  2. 每行數(shù)據(jù)除了用戶定義的列之外,還有兩個隱藏列录肯,事務(wù)ID列回滾指針列趴腋。分別為6字節(jié)和7字節(jié)的大小。若InnoDB表沒有定義主鍵论咏,每行還會增加一個6字節(jié)的rowid列优炬。
  3. 固定長度CHAR字段在未能完全占用其長度空間時,會用0x20來進行填充厅贪。
  4. 記錄頭信息的最后兩個字節(jié)代表next_recorder蠢护,代表下一條記錄的偏移量,所以InnoDB在頁內(nèi)部是通過一種鏈表的結(jié)構(gòu)來串連各個行記錄的养涮。

REDUNDANT

  • Redundant是MySQL5.0版本之前InnoDB的行記錄格式葵硕,其存在是為了兼容老版本的頁格式。
  • Redundant行記錄存儲方式:
  1. 第一部分是一個字段長度偏移列表贯吓,同樣是按列的順序逆序放置的懈凹。

  2. 第二部分是記錄頭信息,不同于Compact悄谐,Redundant占用6字節(jié)(48位)蘸劈,每位含義如下:


  1. 其中n_fields值代表一行中列的數(shù)量,占用10位尊沸。這也解釋了為什么MySQL 一行支持的最多列數(shù)為1023
  • 需要注意的是:
  1. 對于NULL值的處理贤惯,Redundant和Compact非常不同:對于VARCHAR類型的NULL值洼专,Redundant同樣不占用任何空間,但CHAR類型的NULL值需要占用最大值字節(jié)數(shù)大小的空間孵构。

行溢出數(shù)據(jù)

  • InnoDB可以將一條記錄中的某些數(shù)據(jù)存儲在真正的數(shù)據(jù)頁面之外屁商。

  • 是否溢出與列類型是否為BLOB等大對象列類型并無直接關(guān)系。而是根據(jù)“保證一個頁至少能存放兩條記錄”的標(biāo)準(zhǔn)來判斷的。如果VERCHAR類型的列長度過長導(dǎo)致一頁只能存儲一條記錄蜡镶,則也會被放到Uncompressed BLOB Page(行溢出數(shù)據(jù)頁)雾袱。之所以有這個標(biāo)準(zhǔn)的原因,是因為如果不能保證如此官还,那B+Tree就是去意義變成鏈表了芹橡。

  • InnoDB能存放VARCHAR類型的最大長度為65532字節(jié) (注意并非65535,這其中還有其他開銷)望伦。另外要注意林说,VARCHAR(N)中的N指的是字符的長度而非字節(jié)。另外屯伞,MySQL手冊中定義的65535字節(jié)長度是指所有VARCHAR列的長度總和腿箩。

  • 當(dāng)發(fā)生行溢出時,數(shù)據(jù)頁中值保存了列的前768字節(jié)的前綴數(shù)據(jù)劣摇,之后是偏移量珠移,指向行溢出頁。如下圖所示:

Compressed和Dynamic行記錄格式

  • 從InnoDB1.0.x開始引入了新的文件格式(可理解為頁格式):Barracuda末融。而之前的文件格式被稱為Antelope钧惧,Barracuda包含了Antelope:
  • 新的兩種行記錄格式對于存放在BLOB中的數(shù)據(jù)采用了完全的行溢出方式,在數(shù)據(jù)頁中只存放20個字節(jié)的指針滑潘,實際的數(shù)據(jù)都存放子頁OffPage中垢乙。而之前的兩種行記錄格式都是會存放768個前綴字節(jié)。新的行溢出方式如下:
  • Compressed行記錄格式的另一個功能就是:存儲在其中的行數(shù)據(jù)會以zlib的算法進行壓縮语卤。因此對于BLOB追逮、TEXT、VARXCHAR這些大長度類型的數(shù)據(jù)能夠非常有效的存儲粹舵。

CHAR的行存儲結(jié)構(gòu)

  • 從MySQL4.1開始钮孵,CHAR(N)中的N指的是字符的長度,而不是之前版本的字節(jié)長度眼滤。也就是說在不同字符集下巴席,CHAR類型列內(nèi)部存儲的可能不是定長的數(shù)據(jù)
  • 另外由于多字節(jié)的字符編碼诅需,不同字符的長度可能不同漾唉,所以CHAR類型不再代表固定長度的字符串了。因此堰塌,對于多字節(jié)字符編碼的CHAR類型的存儲赵刑,InnoDB在內(nèi)部將其視為變長字符類型。這也就意味著在變長長度列表中會記錄CHAR數(shù)據(jù)類型的長度场刑。只是對于未能占滿長度的字符還是填充0x20般此。

InnoDB數(shù)據(jù)頁結(jié)構(gòu)

  • 通過前面內(nèi)容我們已了解到,頁是InnoDB管理數(shù)據(jù)庫的最小磁盤單位
  • InnoDB數(shù)據(jù)頁由以下七部分組成:

File Header:文件頭

  • File Header用來記錄頁的一些頭信息铐懊,共由如下8部分組成邀桑,共占用38字節(jié):
  • InnoDB頁的類型:

Page Header:頁頭

  • 該部分用來記錄數(shù)據(jù)頁的狀態(tài)信息,由14個部分組成科乎,共56字節(jié):

Infimum和Supremum Record

  • 在InnoDB中壁畸,每個數(shù)據(jù)頁都有兩個虛擬的行記錄,用來限定記錄的邊界喜喂。
  • Infimum記錄是比該頁中任何主鍵值都要小的值瓤摧。
  • Supremum指比任何可能大的值還要大的值。
  • 這兩個值在頁創(chuàng)建時被建立玉吁,且在任何情況下都不會被刪除照弥。
  • 示意圖如下:

User Record和Free Space

  • User Record,用戶記錄进副,即行記錄这揣。
  • Free Space,空閑空間影斑。是個鏈表數(shù)據(jù)結(jié)構(gòu)给赞。在一條記錄被刪除后,該空間會被加入到空閑鏈表中矫户。

Page Directory:頁目錄

  • Page Directory中存放了記錄的相對位置片迅,有時將這些記錄指針稱為Slots()或Directory Slots(目錄槽)。
  • InnoDB中并不是每個記錄都擁有一個槽皆辽,InnoDB的槽是一個稀疏目錄柑蛇,即一個槽中可能包含多個記錄。當(dāng)記錄被插入或刪除時驱闷,需要對槽進行分裂或平衡的維護操作耻台。
  • 在槽中記錄按照索引鍵信息順序存放,這樣可以利用二叉查找迅速找到記錄的指針空另。
  • 需要注意的是:B+樹索引本身并不能找到具體的一條記錄盆耽,能找到只是該記錄所在的頁。數(shù)據(jù)庫把頁載入到內(nèi)存扼菠,然后通過Page Directory再進行二叉查找摄杂。只不過二叉查找的時間復(fù)雜度很低,同時在內(nèi)存中查找很快循榆,因此通常忽略這部分時間匙姜。

File Trailer:文件結(jié)尾信息

  • 為了檢測頁是否已完整地寫入磁盤(如寫入時可能發(fā)生磁盤損壞、機器關(guān)機等)冯痢,InnoDB設(shè)置了File Trailer來保證頁的完整性

MySQL-InnoDB表 - 簡書

MySQL InnoDB存儲引擎之表(一)_chenlvzhou的專欄-CSDN博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市浦楣,隨后出現(xiàn)的幾起案子袖肥,更是在濱河造成了極大的恐慌,老刑警劉巖振劳,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椎组,死亡現(xiàn)場離奇詭異,居然都是意外死亡历恐,警方通過查閱死者的電腦和手機寸癌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弱贼,“玉大人蒸苇,你說我怎么就攤上這事∷甭茫” “怎么了溪烤?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長庇勃。 經(jīng)常有香客問我檬嘀,道長,這世上最難降的妖魔是什么责嚷? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任鸳兽,我火速辦了婚禮,結(jié)果婚禮上罕拂,老公的妹妹穿的比我還像新娘揍异。我一直安慰自己,他們只是感情好聂受,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布蒿秦。 她就那樣靜靜地躺著,像睡著了一般蛋济。 火紅的嫁衣襯著肌膚如雪棍鳖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天碗旅,我揣著相機與錄音渡处,去河邊找鬼。 笑死祟辟,一個胖子當(dāng)著我的面吹牛医瘫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播旧困,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼醇份,長吁一口氣:“原來是場噩夢啊……” “哼稼锅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起僚纷,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤矩距,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后怖竭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锥债,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年痊臭,在試婚紗的時候發(fā)現(xiàn)自己被綠了哮肚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡广匙,死狀恐怖允趟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情艇潭,我是刑警寧澤拼窥,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站蹋凝,受9級特大地震影響鲁纠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鳍寂,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一改含、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧迄汛,春花似錦捍壤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至睹逃,卻和暖如春盗扇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沉填。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工疗隶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翼闹。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓斑鼻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親猎荠。 傳聞我的和親對象是個殘疾皇子坚弱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353