阿里面試被問:MySql數(shù)據(jù)是如何存儲在磁盤上存儲的?

server層格式:與存儲引擎無關(guān),Binlog存儲常用的一種 (Bin Log 我們前面已經(jīng)詳細介紹過了,這個是MySql主從復(fù)制的一個很重要的文件) 索引元組格式:InnoDB存取過程記錄的中間狀態(tài),是InnoDB在內(nèi)存中存儲的格式 (換句話說我們的增刪改的操作都是在內(nèi)存中執(zhí)行的,這個只是一種臨時狀態(tài)) 物理存儲格式:記錄在物理頁面中的存儲格式,即compact格式,與索引元組格式一一對應(yīng)。(這個是數(shù)據(jù)在磁盤存儲的真正的格式)
SHOW TABLE STATUS查看到行的的存儲格式。


varchar為例,假設(shè)現(xiàn)在三個字段,字段類型分別為:varchar(10),char(1),char(1),char大家都是知道的,存儲的基本是一些已知的長度固定的數(shù)據(jù),假設(shè)這三個類型的字段分別有如下的數(shù)據(jù):mysql a a;第二行:dog b c;畫個圖來幫助大家想象,現(xiàn)在你看到的是數(shù)據(jù)中為我們展現(xiàn)的樣子。
mysql a a dog b c,他們在磁盤中都是挨在一起存儲的。MySql在設(shè)計的時候才會使用行格式存儲,才會有前面的哪些變長字段列表和標志位以及記錄信息,這些就是用來記錄一行的記錄的信息,換句話說,MySql是通過這些描述信息來定位到一行中的具體記錄的。MySql是很清楚的,在這個基礎(chǔ)上我們能看明白下面和想通后面的事情。首先我們看到 mysql是5個字符,使用十六進制表示是 0x05,所以他的存儲大概是這樣子的:

MySql這個時候是怎么讀讀取數(shù)據(jù)的了,就是他會先根據(jù)變長字段長度列表中描述的變長字段的信息去查找變長字段,例如第一行,MySql解析到變長字段是5,所以他會在mysql a a dog b c 這些里面取出5個字符,也就是 mysql,緊接著后面是兩個 char(1) 也就是兩個 a 在依次取出來。中間設(shè)備。由淺入深,我們慢慢來,剛剛上面說到的僅僅是一種非常簡單的情況,這個首先是幫助大家理解,讓大家先明白有這么個回事,是這么回事,然后在慢慢的挖掘,我們一定要一個蘿卜一個坑的去踏實學(xué)習(xí)
varchar類型的字段怎么辦?例如:varchar(3),varchar(10),varchar(4),char(1),他有一條記錄是這樣子的:aaa ,bb,cccc,d,你根據(jù)上面的能推測出磁盤中的行記錄是怎么樣子的嗎?0x03,0x02,0x04 null標志位 記錄頭信息 aaa bb cccc d;這么想的同學(xué)請鼻子靠墻:);實際上并不是這樣子的。MySql在 compact 行格式中,把所有變長類型的長度存放在行記錄的開頭部位形成一個列表(這個列表就是剛剛上面說的變長字段列表),按照列的逆序存放,也就是大致是這樣子的:
next_record指針 指向下一行 記錄頭信息和 真實數(shù)據(jù) 之間的位置。因為這個位置剛剛好,向左讀取就是行描述相關(guān)信息,向右讀取就是真實數(shù)據(jù)。正好對應(yīng)變長字段長度列表。畫個圖來幫助大家理解下:
數(shù)據(jù)在磁盤中的存儲在物理空間上面是連續(xù)的 數(shù)據(jù)是被存放在MySql設(shè)計出來的數(shù)據(jù)頁上面的,數(shù)據(jù)頁上面存儲的才是最終的一行一行的記錄 行的存儲格式默認是Compact 每一行數(shù)據(jù)都會有相應(yīng)的行描述部分,描述部分有【變長字段列表】【NULL標志位】【記錄頭信息】 每一行都會有next_record指針,指向記錄頭和變長字段列表的中間某個位置,方便尋址 變長列表中的varchar列的描述是逆序的(和字段的順序相反)這樣做的目的在上圖中描述的很清楚了
MySql又是怎么處理的呢?是不是直接存儲NULL呢。MySql針對與Null直接存儲,他實際上是按照“NULL”這樣字符串的形式存儲的,這樣顯然不行啊,因為字符串要占用空間的啊(一個 NULL 字符串要占用四個字符呢),你都沒有值,還占這么多空間,所以MySql肯定不是這樣存儲的。其實MySql在處理NULL值的時候是會將它通二進制來存儲的,且也是逆序的CREATE TABLE `students` (
`name` varchar(10) NOT NULL,
`address` varchar(255) DEFAULT NULL,
`gender` char(1) DEFAULT NULL,
`class` varchar(10) DEFAULT NULL,
`hobbies` varchar(255) DEFAULT NULL,
PRIMARY KEY (`name`)
)

0x08 0x05
name字段是主鍵,不可能在NULL 標志位中的,又因為 name 是varchar 字段,所以就會去變長字段列中查找,找到值為 0x05 接著就會去字段列表中讀取5個字符的長度,也就是 roles ,第一個字段讀取成功; 接著是 address 字段,因為類型是 MySql 已知的,又因為字段值為 null 所以就不需要去讀取了,第二個字段讀取結(jié)束; 接著是gender字段,是char類型的,直接拿到 f 就可以了; 下一個是class 字段,因為是null 所以根本不會去變長字段中查找; 最后一個是 hobbies 字段,因為不為null ,又是第二個變長字段,這個時候就會去 變長字段列表中查找,結(jié)果定位到是 0x08 那就讀取 8 個字符的長度出來,拿出來是hobby_xx;


0x08 0x05 00000101 0000010100000000000000000000000000000010 21134 44 232343
所以你在使用和了解的使用只需要按照被人的規(guī)則來執(zhí)行,然后在此基礎(chǔ)上深入了解下別人為什么這么設(shè)計?這樣會更有助于我們掌握和理解某個知識點。
關(guān)注公眾號【Java技術(shù)江湖】后回復(fù)“PDF”即可領(lǐng)取200+頁的《Java工程師面試指南》
強烈推薦,幾乎涵蓋所有Java工程師必知必會的知識點,不管是復(fù)習(xí)還是面試,都很實用。

評論
圖片
表情
