MySQL 中的表數據是如何存儲的?
MySQL是基于磁盤進行數據存儲的關系型數據庫, 所有的數據和索引都以磁盤文件的方式存儲, 在有需要時載入內存讀取。MySQL支持多種存儲引擎,不同的存儲引擎保存的文件不同。InnoDB是MySQL使用最為廣泛的存儲引擎,下面我們以InnoDB引擎為例來說明。
當我們創建一個數據庫表時,InnoDB會創建三個文件。其中,ibd后綴的文件是對表數據和索引實際存儲的文件,也稱為表空間文件。
表空間文件的結構由段、區、頁、和行組成。
數據庫表中的記錄都是按行進行存放的,每行記錄根據不同的行格式,有不同的存儲結構。以Compact行格式為例,一條記錄的存儲可以分為兩部分,分別是“額外信息”和“真實數據”。 額外信息用來描述記錄,分為變長字段列表、NULL值列表和記錄頭信息。
雖然記錄是按照行來存儲的,但考慮到效率,數據庫的讀寫并不以行為單位,而是以頁為單位,一個頁中可以存儲多個行記錄。頁的大小默認為16KB,也就是數據庫一次最少從磁盤中讀取16KB的內容到內存,一次最少把內存中16KB的內容刷新到磁盤。
區是比頁大一級的存儲結構,一個區會分配64 個連續的頁。因為頁大小默認是16KB,所以一個區的大小是 64個16KB,也就是1MB。
段由一個或多個區組成,區在文件系統是一個連續分配的空間,不過在段中不要求區與區之間是相鄰的。段是數據庫中的分配單位,不同類型的數據庫對象以不同的段形式存在。當我們創建數據表、索引的時候,就會創建對應的段,比如創建一張表時會創建一個表段,創建一個索引時會創建一個索引段。
表空間存儲的對象是段,在一個表空間中可以有一個或多個段,但是一個段只能屬于一個表空間。數據庫由一個或多個表空間組成。
對于一行數據如何存放,我們需要重點關注變長字段和NULL值。MySQL支持一些變長的數據類型,比如varchar(n),變長字段中存儲多少字節數據是不固定的,所以我們存儲真實數據的時候,需要把這些數據占用的字節數也存起來。
在Compact行格式中,把所有變長字段真實數據占用的字節長度,按照記錄列的逆序方式存放在記錄的開頭部位,形成一個變長字段長度列表。注意當數據表沒有變長字段時,比如全部都是int類型字段,這時候表里的行格式就不會有變長字段長度列表。
另外,Compact行格式還會把可以為NULL的列統一管理起來,以記錄列的逆序方式存放在一個NULL值列表中。標示數據是否為NULL使用一個二進制位表示,1為NULL,0為非NULL,注意,如果表中沒有允許存儲 NULL 的列,則 NULL值列表也不存在。