下次面試我一定問:MySql數(shù)據(jù)是如何存儲(chǔ)在磁盤上存儲(chǔ)的?


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


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

MySql這個(gè)時(shí)候是怎么讀讀取數(shù)據(jù)的了,就是他會(huì)先根據(jù)變長(zhǎng)字段長(zhǎng)度列表中描述的變長(zhǎng)字段的信息去查找變長(zhǎng)字段,例如第一行,MySql解析到變長(zhǎng)字段是5,所以他會(huì)在mysql a a dog b c 這些里面取出5個(gè)字符,也就是 mysql,緊接著后面是兩個(gè) char(1) 也就是兩個(gè) a 在依次取出來。中間設(shè)備。由淺入深,我們慢慢來,剛剛上面說到的僅僅是一種非常簡(jiǎn)單的情況,這個(gè)首先是幫助大家理解,讓大家先明白有這么個(gè)回事,是這么回事,然后在慢慢的挖掘,我們一定要一個(gè)蘿卜一個(gè)坑的去踏實(shí)學(xué)習(xí)
varchar類型的字段怎么辦?例如:varchar(3),varchar(10),varchar(4),char(1),他有一條記錄是這樣子的:aaa ,bb,cccc,d,你根據(jù)上面的能推測(cè)出磁盤中的行記錄是怎么樣子的嗎?0x03,0x02,0x04 null標(biāo)志位 記錄頭信息 aaa bb cccc d;這么想的同學(xué)請(qǐng)鼻子靠墻:);實(shí)際上并不是這樣子的。MySql在 compact 行格式中,把所有變長(zhǎng)類型的長(zhǎng)度存放在行記錄的開頭部位形成一個(gè)列表(這個(gè)列表就是剛剛上面說的變長(zhǎng)字段列表),按照列的逆序存放,也就是大致是這樣子的:
next_record指針 指向下一行 記錄頭信息和 真實(shí)數(shù)據(jù) 之間的位置。因?yàn)檫@個(gè)位置剛剛好,向左讀取就是行描述相關(guān)信息,向右讀取就是真實(shí)數(shù)據(jù)。正好對(duì)應(yīng)變長(zhǎng)字段長(zhǎng)度列表。畫個(gè)圖來幫助大家理解下:
數(shù)據(jù)在磁盤中的存儲(chǔ)在物理空間上面是連續(xù)的 數(shù)據(jù)是被存放在MySql設(shè)計(jì)出來的數(shù)據(jù)頁(yè)上面的,數(shù)據(jù)頁(yè)上面存儲(chǔ)的才是最終的一行一行的記錄 行的存儲(chǔ)格式默認(rèn)是Compact 每一行數(shù)據(jù)都會(huì)有相應(yīng)的行描述部分,描述部分有【變長(zhǎng)字段列表】【NULL標(biāo)志位】【記錄頭信息】 每一行都會(huì)有next_record指針,指向記錄頭和變長(zhǎng)字段列表的中間某個(gè)位置,方便尋址 變長(zhǎng)列表中的varchar列的描述是逆序的(和字段的順序相反)這樣做的目的在上圖中描述的很清楚了
MySql又是怎么處理的呢?是不是直接存儲(chǔ)NULL呢。MySql針對(duì)與Null直接存儲(chǔ),他實(shí)際上是按照“NULL”這樣字符串的形式存儲(chǔ)的,這樣顯然不行啊,因?yàn)樽址加每臻g的?。ㄒ粋€(gè) NULL 字符串要占用四個(gè)字符呢),你都沒有值,還占這么多空間,所以MySql肯定不是這樣存儲(chǔ)的。其實(shí)MySql在處理NULL值的時(shí)候是會(huì)將它通二進(jìn)制來存儲(chǔ)的,且也是逆序的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 標(biāo)志位中的,又因?yàn)?name 是varchar 字段,所以就會(huì)去變長(zhǎng)字段列中查找,找到值為 0x05 接著就會(huì)去字段列表中讀取5個(gè)字符的長(zhǎng)度,也就是 roles ,第一個(gè)字段讀取成功; 接著是 address 字段,因?yàn)轭愋褪?MySql 已知的,又因?yàn)樽侄沃禐?null 所以就不需要去讀取了,第二個(gè)字段讀取結(jié)束; 接著是gender字段,是char類型的,直接拿到 f 就可以了; 下一個(gè)是class 字段,因?yàn)槭莕ull 所以根本不會(huì)去變長(zhǎng)字段中查找; 最后一個(gè)是 hobbies 字段,因?yàn)椴粸閚ull ,又是第二個(gè)變長(zhǎng)字段,這個(gè)時(shí)候就會(huì)去 變長(zhǎng)字段列表中查找,結(jié)果定位到是 0x08 那就讀取 8 個(gè)字符的長(zhǎng)度出來,拿出來是hobby_xx;


0x08 0x05 00000101 0000010100000000000000000000000000000010 21134 44 232343
所以你在使用和了解的使用只需要按照被人的規(guī)則來執(zhí)行,然后在此基礎(chǔ)上深入了解下別人為什么這么設(shè)計(jì)?這樣會(huì)更有助于我們掌握和理解某個(gè)知識(shí)點(diǎn)。
往期推薦

特普朗任期最后一天特赦了一位硅谷工程師,免去牢獄之災(zāi)和2億美金賠款

鄭爽和張恒糾紛的前因后果:一個(gè)APP引發(fā)的血案

被讀者投訴抄襲了!?
直面Java第343期:為什么TOMCAT要破壞雙親委派
深入并發(fā)第013期:拓展synchronized——鎖優(yōu)化
評(píng)論
圖片
表情
