InnoDB存儲(chǔ)空間

關(guān)鍵詞
  • 表空間、段、區(qū)、頁(yè)、行
  • 一個(gè)段256M,一個(gè)區(qū)1M,一個(gè)頁(yè)16K,一個(gè)段=256區(qū)=256*64個(gè)頁(yè)
  • 表空間中每連續(xù)256個(gè)區(qū)需要一個(gè)XDES來(lái)維護(hù),XDES里面有256個(gè)entry,每一個(gè)entry描述一個(gè)區(qū)的狀態(tài)、區(qū)里面64個(gè)頁(yè)的狀態(tài)、上一個(gè)和下一個(gè)區(qū)的指針、區(qū)屬于哪一個(gè)段。
  • 段分為數(shù)據(jù)段,索引段,回滾段等,在 MySQL中,數(shù)據(jù)是按照B+樹來(lái)存儲(chǔ),因此數(shù)據(jù)即索引,因此數(shù)據(jù)段的頁(yè)即為B+樹的葉子節(jié)點(diǎn),索引段的頁(yè)為B+樹的非葉子節(jié)點(diǎn)。
  • Page鏈接起來(lái)就是一個(gè)雙向鏈表的結(jié)構(gòu)
  • B+ 樹在查找對(duì)應(yīng)的記錄時(shí),并不會(huì)直接從樹中找出對(duì)應(yīng)的行記錄,它只能獲取記錄所在的頁(yè),將整個(gè)頁(yè)加載到內(nèi)存中,再通過 Page Directory 中存儲(chǔ)的稀疏索引和 n_owned、next_record 屬性取出對(duì)應(yīng)的記錄

https://blog.jcole.us/2013/01/04/page-management-in-innodb-space-files/
https://blog.jcole.us/innodb/

索引組織表

層級(jí)劃分


??InnoDB 實(shí)現(xiàn)的表空間是在文件系統(tǒng)之上又構(gòu)建的一層邏輯存儲(chǔ)的空間管理
??InnoDB 最小讀寫單位是 Page,page 采用默認(rèn)的 16K
??為了高效管理,又將連續(xù)的 64 個(gè)頁(yè)稱為 “extent”,還在 extents 上層添加了一個(gè) segment inode 管理,最多可以管理 256 個(gè) extents
??一個(gè)表空間文件,實(shí)際就是一系列 Pages 的組合 (最大 232),為了方便管理,你可以理解為做了三級(jí)的劃分,分別是 segment、extent、page 。
??段:ibd表空間文件會(huì)被分成多個(gè)段(segment),每個(gè)段和一個(gè)索引關(guān)聯(lián)
??區(qū):段以區(qū)(extent)為大小進(jìn)行增長(zhǎng)或縮小,一個(gè)區(qū)只能屬于一個(gè)段,并且大小為1MB
??頁(yè):頁(yè)(page)是區(qū)的子元素,默認(rèn)大小16KB
??行:一個(gè)頁(yè)可以包含2到N行數(shù)據(jù),這取決與每個(gè)行的大小,但因?yàn)橄拗屏俗钚〈娣?行數(shù)據(jù),所以每一行的大小必須小于8000bytes
??1段 = 256區(qū) = 256*64頁(yè)

查看頁(yè)信息
查看每個(gè)頁(yè)的詳細(xì)信息
innodb_page_info -v dept_emp.ibd

??也可以使用py_innodb_page_info工具

> python py_innodb_page_info.py/usr/local/mysql/data/ibdata1 
Total number of page:83584
Insert Buffer Free List:204 
Freshly Allocated Page:5467 
Undo Log Page:38675
File Segment inode:4 
B-tree Node:39233 
File Space Header:1

??可以看到共有83 584個(gè)頁(yè),其中插入緩沖的空閑列表有204個(gè)頁(yè)、5467個(gè)可用頁(yè)、38 675個(gè)Undo頁(yè)、39 233個(gè)數(shù)據(jù)頁(yè),等等。你可以通過添加-v參數(shù)來(lái)查看更詳細(xì)的內(nèi)容。

表空間

??Space File 主要包括了兩類:系統(tǒng)空間 (system space) 和 表空間 (Per-table space files)
??表空間需要打開 innodb_file_per_table 變量之后才會(huì)生效
??Page0 肯定是 “File SPace HeaDeR”,其中維護(hù)了 extent 相關(guān)的信息,例如那些是空閑的、滿的、有碎片的 (fragmented)。在 FSP_HDR 頁(yè)中,只能維護(hù) 256 個(gè) extent 相關(guān)的信息 ( 256 extent==16,384 pages==256MiB),這也就導(dǎo)致每隔 256M 都需要有一個(gè) XDES 來(lái)管理接下來(lái)的 extent 元信息。

  • File Segment ID:extent屬于哪個(gè)段
  • List node for XDES list:指向上一個(gè)和下一個(gè)extent
  • State:區(qū)狀態(tài)
  • Page State Bitmap:區(qū)里面每一個(gè)頁(yè)的狀態(tài),一個(gè)頁(yè)的狀態(tài)用2個(gè)位表示,一個(gè)區(qū)1M,一個(gè)頁(yè)16K,一個(gè)區(qū)=64個(gè)頁(yè),64 x 2 = 128 bits = 16bytes

??表空間是由不同的段組成的,常見的段有:數(shù)據(jù)段,索引段,回滾段等等。
??在 MySQL中,數(shù)據(jù)是按照B+樹來(lái)存儲(chǔ),因此數(shù)據(jù)即索引,因此數(shù)據(jù)段的頁(yè)即為B+樹的葉子節(jié)點(diǎn),索引段的頁(yè)為B+樹的非葉子節(jié)點(diǎn)。
??回滾段用于存儲(chǔ)undo日志,用于事務(wù)失敗后數(shù)據(jù)回滾以及在事務(wù)未提交之前通過undo日志獲取之前版本的數(shù)據(jù),在InnoDB1.1版本之前一個(gè)InnoDB,只支持一個(gè)回滾段,支持1023個(gè)并發(fā)修改事務(wù)同時(shí)進(jìn)行,在InnoDB1.2版本,將回滾段數(shù)量提高到了128個(gè),也就是說(shuō)可以同時(shí)進(jìn)行128*1023個(gè)并發(fā)修改事務(wù)。
??每個(gè)段在開始時(shí),會(huì)根據(jù)數(shù)據(jù)量的需要,逐步增加頁(yè)的數(shù)量,當(dāng)頁(yè)數(shù)量超過32頁(yè)時(shí),會(huì)以64個(gè)頁(yè)為單位,增大頁(yè)數(shù)量。

??使用py_innodb_page_info工具時(shí),page level等于0000的,表示葉子節(jié)點(diǎn),B-tree Node是葉子節(jié)點(diǎn)和非葉子節(jié)點(diǎn)的總數(shù)。葉子節(jié)點(diǎn)屬于數(shù)據(jù)段。

頁(yè)

innoDB存儲(chǔ)引擎中,常見的頁(yè)類型有:

  1. 數(shù)據(jù)頁(yè)(B-tree Node)
  2. undo頁(yè)(undo Log Page)
  3. 系統(tǒng)頁(yè) (System Page)
  4. 事物數(shù)據(jù)頁(yè) (Transaction System Page)
  5. 插入緩沖位圖頁(yè)(Insert Buffer Bitmap)
  6. 插入緩沖空閑列表頁(yè)(Insert Buffer Free List)
  7. 未壓縮的二進(jìn)制大對(duì)象頁(yè)(Uncompressed BLOB Page)
  8. 壓縮的二進(jìn)制大對(duì)象頁(yè) (compressed BLOB Page)

??我們重點(diǎn)關(guān)注和數(shù)據(jù)組織結(jié)構(gòu)相關(guān)的字段:Page的頭部保存了兩個(gè)指針,分別指向前一個(gè)Page和后一個(gè)Page,頭部還有Page的類型信息和用來(lái)唯一標(biāo)識(shí)Page的編號(hào)。根據(jù)這兩個(gè)指針我們很容易想象出Page鏈接起來(lái)就是一個(gè)雙向鏈表的結(jié)構(gòu)

數(shù)據(jù)頁(yè)

??頁(yè)是 InnoDB 存儲(chǔ)引擎管理數(shù)據(jù)的最小磁盤單位,而 B-Tree 節(jié)點(diǎn)就是實(shí)際存放表中數(shù)據(jù)的頁(yè)面。

??每一個(gè)頁(yè)中包含了兩對(duì) header/trailer:內(nèi)部的 Page Header/Page Directory 關(guān)心的是頁(yè)的狀態(tài)信息,而 Fil Header/Fil Trailer 關(guān)心的是記錄頁(yè)的頭信息。
??在頁(yè)的頭部和尾部之間就是用戶記錄和空閑空間了,每一個(gè)數(shù)據(jù)頁(yè)中都包含 Infimum 和 Supremum 這兩個(gè)虛擬的記錄(可以理解為占位符),Infimum 記錄是比該頁(yè)中任何主鍵值都要小的值,Supremum 是該頁(yè)中的最大值:
??User Records 就是整個(gè)頁(yè)面中真正用于存放行記錄的部分,而 Free Space 就是空余空間了,它是一個(gè)鏈表的數(shù)據(jù)結(jié)構(gòu),為了保證插入和刪除的效率,整個(gè)頁(yè)面并不會(huì)按照主鍵順序?qū)λ杏涗涍M(jìn)行排序,它會(huì)自動(dòng)從左側(cè)向右尋找空白節(jié)點(diǎn)進(jìn)行插入,行記錄在物理存儲(chǔ)上并不是按照順序的,它們之間的順序是由 next_record 這一指針控制的。
??B+ 樹在查找對(duì)應(yīng)的記錄時(shí),并不會(huì)直接從樹中找出對(duì)應(yīng)的行記錄,它只能獲取記錄所在的頁(yè),將整個(gè)頁(yè)加載到內(nèi)存中,再通過 Page Directory 中存儲(chǔ)的稀疏索引和 n_owned、next_record 屬性取出對(duì)應(yīng)的記錄,不過因?yàn)檫@一操作是在內(nèi)存中進(jìn)行的,所以通常會(huì)忽略這部分查找的耗時(shí)。
??page分為葉子頁(yè)(leaf page)和非葉子節(jié)頁(yè)(non-leaf page),葉子頁(yè)包含了實(shí)際的行數(shù)據(jù),非葉子頁(yè)只包含了非葉子頁(yè)指針或葉子頁(yè)指針。B+樹是平衡的,所以所有的分支都有一樣的深度。
??InnoDB為每一個(gè)page分配了一個(gè)level級(jí)別:葉子頁(yè)的level是0,隨著樹分支往上走,level不斷遞增。
??所有的非root頁(yè)和非葉子頁(yè)的頁(yè)面,都被稱為internal page。
??無(wú)論是葉子頁(yè)還是非葉子頁(yè), 里面包含的行(record)都有指向下一行的指針(在同一個(gè)page里的偏移量),record鏈表從infimum開始,按鍵升序鏈接所有記錄,終止于supremum。需要注意的時(shí),在page里面的record數(shù)據(jù),從物理角度來(lái)講,在page里面并不是順序存儲(chǔ),行在插入到page時(shí),哪里有空缺空間就會(huì)插入到哪里,所以它們需要依賴的順序只有鏈表上的順序。
??同一個(gè)level的page,每一個(gè)page會(huì)有一個(gè)指針(FIL頭部)指向上一個(gè)和下一個(gè)page

??InnoDB存儲(chǔ)引擎提供了Compact和Redundant兩種格式來(lái)存放行記錄數(shù)據(jù)。
??SHOW TABLE STATUS LIKE “table_name”,命令可以查看行格式
Compact

  • 變長(zhǎng)字段長(zhǎng)度列表:此字段標(biāo)識(shí)列字段的長(zhǎng)度,與列字段順序相反存放,若列長(zhǎng)度小于255字節(jié),用一個(gè)字節(jié)表示,若大于255字節(jié),用兩個(gè)字節(jié)表示,這也是 MySQL的VARCHAR類型最大長(zhǎng)度限制為65535
  • NULL標(biāo)志位:標(biāo)識(shí)改列是否有空字段,有用1表示,否則為0,該標(biāo)志位長(zhǎng)度為ceil(N/8)(此處是 MySQL技術(shù)內(nèi)幕-InnoDB存儲(chǔ)引擎與官方文檔有出入的地方);
  • 記錄頭信息:固定用5字節(jié)表示,具體含義如下:


  • 列數(shù)據(jù):此行存儲(chǔ)著列字段數(shù)據(jù),Null是不占存儲(chǔ)空間的;
  • 隱藏列:事務(wù)id和回滾列id,分別占用6、7字節(jié),若此表沒有主鍵,還會(huì)增加6字節(jié)的rowid列。
    Redundant
  • 字段長(zhǎng)度偏移列表:存儲(chǔ)字段偏移量,與列字段順序相反存放,若列長(zhǎng)度小于255字節(jié),用一個(gè)字節(jié)表示,若大于255字節(jié),用兩個(gè)字節(jié)表示
  • 記錄頭信息:固定用6字節(jié)表示,具體含義如下:


  • 隱藏列:事務(wù)id和回滾列id,分別占用6、7字節(jié),若此表沒有主鍵,還會(huì)增加6字節(jié)的rowid列。
    行溢出
    ??關(guān)于行溢出,即Redundant格式、Compact格式存儲(chǔ)很長(zhǎng)的字符串,在該字段會(huì)存儲(chǔ)該字符串的前768個(gè)字節(jié)的前綴(字段超過768字節(jié)則為變長(zhǎng)字段),并將整個(gè)字符串存儲(chǔ)在uncompress blob頁(yè)中。

索引

??InnoDB 存儲(chǔ)引擎在絕大多數(shù)情況下使用 B+ 樹建立索引,B+ 樹是平衡樹,它查找任意節(jié)點(diǎn)所耗費(fèi)的時(shí)間都是完全相同的,比較的次數(shù)就是 B+ 樹的高度。當(dāng)數(shù)據(jù)必須從磁盤讀取時(shí),B+樹可以保證最多的讀取次數(shù)(取決于樹的高度)。
聚集索引和輔助索引

??數(shù)據(jù)庫(kù)中的 B+ 樹索引可以分為聚集索引(clustered index)和輔助索引(secondary index),它們之間的最大區(qū)別就是,聚集索引中存放著一條行記錄的全部信息,而輔助索引中只包含索引列和一個(gè)用于查找對(duì)應(yīng)行記錄的『書簽』。
聚集索引
??聚集索引就是按照表中主鍵的順序構(gòu)建一顆 B+ 樹,并在葉節(jié)點(diǎn)中存放表中的行記錄數(shù)據(jù)。

??所有正常的表應(yīng)該有且僅有一個(gè)聚集索引(絕大多數(shù)情況下都是主鍵),表中的所有行記錄數(shù)據(jù)都是按照聚集索引的順序存放的。
??當(dāng)我們使用聚集索引對(duì)表中的數(shù)據(jù)進(jìn)行檢索時(shí),可以直接獲得聚集索引所對(duì)應(yīng)的整條行記錄數(shù)據(jù)所在的頁(yè),不需要進(jìn)行第二次操作。

輔助索引
??數(shù)據(jù)庫(kù)將所有的非聚集索引都劃分為輔助索引,但是這個(gè)概念對(duì)我們理解輔助索引并沒有什么幫助;輔助索引也是通過 B+ 樹實(shí)現(xiàn)的,但是它的葉節(jié)點(diǎn)并不包含行記錄的全部數(shù)據(jù),僅包含索引中的所有鍵和一個(gè)用于查找對(duì)應(yīng)行記錄的『書簽』,在 InnoDB 中這個(gè)書簽就是當(dāng)前記錄的主鍵。

??如果在表 users 中存在一個(gè)輔助索引 (first_name, age),那么它構(gòu)成的 B+ 樹大致就是上圖這樣,按照 (first_name, age) 的字母順序?qū)Ρ碇械臄?shù)據(jù)進(jìn)行排序,當(dāng)查找到主鍵時(shí),再通過聚集索引獲取到整條行記錄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,238評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,430評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,134評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,893評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,653評(píng)論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,136評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,212評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,372評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,888評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,738評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,939評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,482評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,179評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,588評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,829評(píng)論 1 283
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,610評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,916評(píng)論 2 372