MySQL(十三)】Innodb 表空間

數據的基本單位是頁,而頁又屬於各種表空間,比如系統表空間和獨立表空間等。表空間裏是如何組織數據的?

這裏主要看下獨立表空間的情況。

每64個連續的頁組成一個區(extent),頁的大小是16kb,一個區大小也就是1mb。每256個區呢又可以劃分爲一個組,表空間內是以組爲單位管理空間的,如下所示:

(本篇圖片全部來自掘金小冊中《MySQL是怎樣運行的》一書)

爲啥要創建區的概念?因爲相鄰的頁是由指針連接的,並且是排序的,訪問一個頁時,很可能要訪問相鄰的頁,比如b+樹的葉子節點,我們在查找時便會訪問相鄰的頁。所以,相鄰的頁最好在物理上也是連續的,這樣可以減少io成本。所以說,申請頁在一定程度上可以理解爲申請區,然後將區裏連續的頁分配出去,保證查詢的效率(這下應該知道爲什麼儘量使用自增主鍵索引了吧)。

“一定程度”是啥意思?也就是說存在不以區爲單位分配空間的場景唄?是的。想一下,對於一個數據量很少的表,只有幾行數據,卻直接分配一塊1mb大小的空間?這有點浪費。所以,innodb分配空間的邏輯其實是這樣的:

1.先從一些零散的頁裏找空閒頁分配;

2.如果一個表佔用的空間已經超過了32個零散的頁,那麼後續的空間分配再從表空間的區裏按區爲單位分配;

啥是零散的頁?

每一個表空間裏都會有一些區,這些區專門爲剛纔說的那些小表用的,也就是說這些區的頁可能屬於a表也可能屬於b表。

段的概念

之前說過,爲了讓頁是連續的,相鄰的頁是組織在一塊區上的。但是表裏數據有很多類型,這個組織是分了類的。比如,索引節點和葉子節點的頁就沒必要放一起了。這就引入的段的概念,段是邏輯概念,物理上可能是不連續的。每一個索引就包含了兩個段:索引節點段和數據段。每一個段包含了零散的區+整塊的區。前面說到的那些零散的頁是屬於某一個表空間的,而之後的整塊的區則是屬於某一個段的。不同的索引從不同的段裏申請。

每一個區裏的這64個頁,innodb當然需要存儲本區裏的統計信息了,這樣纔好管理啊。innodb使用叫做XDES Entry的結構來管理一個區:

(本篇圖片全部來自掘金小冊中《MySQL是怎樣運行的》一書)

segment id:區可能是屬於某一個段的,這是段號;

stat:本區的狀態,共有4種。未被使用的區;有空閒狀態的零散區;無空閒狀態的零散區;屬於某一段的區;

page stat bitmap:16字節,128bit,每一個區裏有64個頁,這樣的話,用2個bit代表每一個頁的狀態,實際上只用了一個bit,表示這個頁是否滿了;

list node:使得每一個xdes entry可以組成雙向鏈表,爲啥要組成雙向鏈表?之前不是說分配頁時,先從表空間裏的存零散頁的區分配,再從段裏的區分配?innodb需要將這些區組成不同的鏈表,這樣纔好分配呀。

對於表空間內零散頁組成的區,總共有3種鏈表:

1.FREE鏈表:未被使用的區;

2.FREE_FRAG鏈表:所有仍然有零散頁可分配的區的鏈表;

3.FULL_FRAG鏈表:沒有零散頁可分配的區的鏈表;

對於段內的區,也有類似的三個鏈表:FREE鏈表;BOT_FULL鏈表;FULL鏈表;

接下來 看一下的結構:

(本篇圖片全部來自掘金小冊中《MySQL是怎樣運行的》一書)

我們知道,段是一些零散的頁和段內的區組成的邏輯空間。那麼這些信息怎麼管理?就是通過上面的這個INODE Entry結構管理的,一個entry對應一個段。

藍色部分的三個list就是之前介紹的三個鏈表頭結點。下面的Fragment Array Entry代表的是每一個零散的頁的頁號。那麼,通過這麼一個entry結構,innodb就能知道一個段裏所有的頁和區了。

特殊的頁類型

我們知道頁有各種類型,上一篇我們看過index page類型的頁,是用來存儲索引數據和數據,這裏我們看下與表空間有關的其他的頁類型。

FSP_HDR類型

這是表空間裏的第一個組的第一個頁的類型。其實就是表空間下的第一個頁了,所以這個頁的功能是存這個表空間的一些信息。

(本篇圖片全部來自掘金小冊中《MySQL是怎樣運行的》一書)

File Header和File Trailer是頁的通用信息,之前介紹過了。

File Space Header:存表空間信息,具體如下:

(本篇圖片全部來自掘金小冊中《MySQL是怎樣運行的》一書)

中間部分的三個list,就是存前面提到的表空間零散頁的區的三個鏈表的頭結點的。最後的兩個list後面再說。

entry x:是本組內的各個區的XDES Entry,結果之前也介紹過;這裏順便說下爲啥一個組只能有265個區?因爲每一組內的XDES Entry都是存在組內特定的一個頁內的,而一個頁只能有16kb空間,所以只能存265個區,上一個圖裏頁說了。

XDES類型

從第二組開始,每一個組的第一個頁。存的是本組內的信息。

(本篇圖片全部來自掘金小冊中《MySQL是怎樣運行的》一書)

看了下,其實和FSP_HDR類型的頁結構沒啥區別啊。對啊,確實是,只是少了File Space Header,因爲這個信息只需要在FSP_HDR類型的頁記錄就好。

IBUF_BITMAP類型:

每一個組的第二個頁面。存儲change buffer信息(todo)。

INODE類型:

每一個組的第三個頁面,主要用於存儲INODE Entry結構。

(本篇圖片全部來自掘金小冊中《MySQL是怎樣運行的》一書)

裏面每一個entry都是一個段。

List Node for INODE Page list:這又是啥list???因爲段是邏輯概念,所以理論上可能有多個,那麼也就會有多個entry了,那麼一個頁內可能就存不下了,所以INODE類型的頁也是list,這個結構就是list的前後指針。

再回到之前FSP_HDR類型頁的遺留問題,File Space Header裏最後的兩個鏈表是啥意思?

SEG_INODES_FULL鏈表:滿了的INODE類型的頁面鏈表,存不下entry了。

SEG_INODES_FREE鏈表:仍然有空間的INODE類型的頁面鏈表。

 

鏈表有好多啊。。。

 

最後推薦一下掘金小冊中《MySQL是怎樣運行的》一書,本篇也算是對其中一些內容的小結。

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