4 mysql底層解析——innodb文件系統基本結構(段、簇、頁面),包括連接、解析、緩存、引擎、存儲等

上一篇,我們學習了innodb文件系統的大的框架,知道了innodb文件系統是由一些log和每個表的ibd(16K的整數倍)等文件組成的。那麼這些文件,裏面是怎麼樣的呢?

表數據文件IBD

上一篇我們看到了,當你新建一個庫時,首先文件系統上會多一個以庫名命名的文件夾。裏面有ibd、frm文件,每個表對應一個ibd文件。

那麼當我們新建庫時,innodb做了什麼呢?會初始化一個名叫ibdata1的表空間文件,用來存儲所有該庫的表數據,以及一些系統表,列等系統信息。還會存儲將來做事務時用來保證數據完整性的回滾段數據。

上一篇我們學過了,不同的表既可以共用一個ibd文件,也可以每個表自己一個ibd文件,默認是一個表一個。

但是需要注意的是,雖然是一個表一個ibd,但這個ibd裏只存儲了該表的B+樹數據、索引、插入緩存等信息,其餘的信息如列、屬性等信息還是存儲在默認的ibdata1裏面的。

那麼ibd裏到底是什麼數據呢?答案就是該表的所有索引數據。

相信很多人就要迷茫了,索引不就是相當於目錄嗎,那每行數據跑哪裏去了。要是研究過B+ tree的人應該不會迷茫,沒看過的可能還以爲數據庫是個TXT文件呢,一行數據佔文本一行。其實不是的,索引裏就包含了所有數據。

如果有迷茫的,還是先看這一篇,https://blog.csdn.net/tianyaleixiaowu/article/details/94552675   或者在網上找找B+ tree原理看看,後面也會講。B+ tree的葉子節點,就會存放所有的數據。整個表,其實就是一棵B+ tree,一個ibd就是1-N個b+ tree。N等於你的索引數量。

當你新建一個表時,你會給表創建一個主鍵primary Key,然後這個key就帶着整行數據佔據着一塊空間,作爲B+ tree的一個葉子節點裏元素,將來要找數據,就要靠這個主鍵了。你可以理解爲一個key-value鍵值對,key就是主鍵,value就是整行數據。如果你根本就沒創建主鍵(不推薦),那innodb也會給你分配一個RowId來作爲將來找它的主鍵,雖然你看不到。

這棵擁有全量數據的b+ tree,就是將來提供數據的樹了,一般來說,這棵樹最大也就4層,3層就能存2千萬數據了,4層就很多個億了,將來通過主鍵查詢時,通過2-4次IO就能找到數據行。這個索引樹,我們給它起了個名字——聚簇索引。

是不是終於看到面試點了,談談聚簇索引和二級索引(非聚簇索引)。

二級索引就是你平時創建的那些索引了,可以建多個,建在一個列或者多個列上。這些索引也會構成B+ tree,和聚簇索引的區別就是它不需要存每行的詳細數據,它的葉子節點只需要存primary key或(rowId)(當然還有主鍵索引所在磁盤的位置PageNo)。將來能讓你通過這個索引找到數據行的ID就行了。要查數據時,就根據ID去聚簇索引那棵大樹去查就是了,這就是回表

最後,索引是方便查詢的,索引列的數據不適合放大的,它佔用的空間一多,那麼B+ tree一層中能放的個數就越少。索引列一多,插入就越慢,如果沒有索引,插入一行時只需要對主鍵進行排序即可。如果有很多列都有索引,那麼插入時,就要做很多次排序。

數據文件格式

之前已經知道了,磁盤最小單位是512字節,操作系統是4KB,mysql裏最小的是page(頁面)有16K。現在也知道了ibd就是放索引樹的,那總不能一個樹就攤在一個txt文檔裏吧,所以必須還要有一種文件組織結構。所有的數據都放在page裏,得用一種規則來把N個page連一起,讓它們形成一些關聯,才能將來好查詢,要先找到page,再找到page內的數據。

文件格式包括段、簇、頁面。

這是一個邏輯概念,並不是一個實際存在的文件。它是構成索引的基本元素,當你創建一個B+ tree索引時,會同時創建兩個段。

他們是內節點段和葉子段,內節點段用來管理B+ tree裏非葉子節點的數據,葉子段用來管理葉子節點的數據。葉子和非葉子應該知道是什麼了,裏面存的東西都是什麼應該也清楚,如果還不知道,建議切蛋自盡。

內節點段負責管理那些非葉子節點的分裂啊、增長啊、刪除啊,葉子端就負責行數據的相關動作。

這玩意比段要低一級,段是個邏輯概念,段內部就是多個簇(Extent)組成的。一個簇是物理上連續分配的一段空間,(連續很重要)。每個段至少會有一個簇,在創建一個段時就會創建一個默認的簇,一個簇的大小默認是64個Page(頁面),所以一個簇就是64*16K的硬盤空間。

當往段裏寫入數據後,就是往簇裏寫數據,簇可是硬盤空間。當一個簇已經放不下時,就會再來一個簇,等於又多了一塊64*16K的連續硬盤空間。段可以無限大,注意,每個簇是一塊連續的硬盤空間,但多個簇之間可不是連續的。

同樣,兩個段之間,在硬盤上也沒有什麼關係。

頁面

每個簇裏有64個頁面,都會進行編號,頁面就是最小的存儲單元了。這個簇裏的每個頁面都是連續的一段空間,往裏面寫數據時,就會一個頁面一個頁面的寫入,一個頁面佔滿了,就去下一個頁面。一個頁面16K,放主鍵如int型能放好幾千,放一行數據,譬如1K一行,能放十幾行。這裏就需要注意了,一行數據儘量不要過大,一旦跨page了,就會對性能產生影響。本來一個page就能查出來,結果每次要查2個page,那性能就丟了一倍。

其他

一個表,佔用一個表空間,創建一個表空間時,至少有一個文件(0號文件),這個文件的第一個頁面page,page_no=0,這個page中存儲了這個表空間中,所有段、簇、頁管理的入口。裏面有如下信息:

FSP_SPACE_ID:表空間的唯一ID號

FSP_SIZE:當前表空間的總頁面數

FSP_FREE:一個鏈表(存儲了所有空閒簇(空閒的、新分配的),反正就是所有暫時沒用的簇的指針,不用了就放這個鏈表,要用時,就從這裏拿)

FSP_FREE_FRAG:上面那個是完全空閒的簇,這個裏面是半滿的,裏面不是全空,是有部分頁面被佔用的

FSP_FULL_FRAG:所有被佔滿了的簇的鏈表頭指針

等等,還有很多信息。目的當然就是將各個空間都管理起來,滿的空的,等等各種指針,將來好做數據的增刪改查。

 

 

 

 

 

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