26 一行數(shù)據(jù)中的多個(gè)NULL字段值在磁盤上怎么存儲(chǔ)?

一行數(shù)據(jù)中的多個(gè)NULL字段值在磁盤上怎么存儲(chǔ)?
1、為什么一行數(shù)據(jù)里的NULL值不能直接存儲(chǔ)?
之前我們已經(jīng)給大家講了在數(shù)據(jù)庫里一行數(shù)據(jù)中如果有VARCHAR(10)之類的變長字段,那么他的存儲(chǔ)和讀取會(huì)有什么問題,以及為了解決這個(gè)問題,為什么要給磁盤上存儲(chǔ)的每一行數(shù)據(jù)都加入變長字段長度列表。
今天我們繼續(xù)給大家講解在磁盤上存儲(chǔ)的一行數(shù)據(jù)里另外一塊特殊的數(shù)據(jù)區(qū)域,就是NULL值列表。
這個(gè)所謂的NULL值列表,顧名思義,說的就是你一行數(shù)據(jù)里可能有的字段值是NULL,比如你有一個(gè)name字段,他是允許為NULL的,那么實(shí)際上在存儲(chǔ)的時(shí)候,如果你沒給他賦值,他這個(gè)字段的值就是NULL。
好,那么假設(shè)這個(gè)字段的NULL值我們在磁盤上存儲(chǔ)的時(shí)候,就是按照“NULL”這么個(gè)字符串來存儲(chǔ),是不是很浪費(fèi)存儲(chǔ)空間?
本來他就是個(gè)NULL,說明什么值都沒有,你還給他存?zhèn)€“NULL”字符串,你說你這是干什么呢?
所以實(shí)際在磁盤上存儲(chǔ)數(shù)據(jù)的時(shí)候,一行數(shù)據(jù)里的NULL值是肯定不會(huì)直接按照字符串的方式存放在磁盤上浪費(fèi)空間的。
2、NULL值是以二進(jìn)制bit位來存儲(chǔ)的
我們接著看,那么NULL值列表在磁盤上到底應(yīng)該如何存儲(chǔ)呢?
很簡單,對所有的NULL值,不通過字符串在磁盤上存儲(chǔ),而是通過二進(jìn)制的bit位來存儲(chǔ),一行數(shù)據(jù)里假設(shè)有多個(gè)字段的值都是NULL,那么這多個(gè)字段的NULL,就會(huì)以bit位的形式存放在NULL值列表中。
現(xiàn)在我們來給大家舉個(gè)例子,假設(shè)你有一張表,他的建表語句如下所示:
CREATE TABLE customer (
name VARCHAR(10) NOT NULL,
address VARCHAR(20),
gender CHAR(1),
job VARCHAR(30),
school VARCHAR(50)
) ROW_FORMAT=COMPACT;
上面那個(gè)表就是一個(gè)假想出來的客戶表,里面有5個(gè)字段,分別為name、address、genderjob、school,就代表了客戶的姓名、地址、性別、工作以及學(xué)校。
其中有4個(gè)變長字段,還有一個(gè)定長字段,然后第一個(gè)name字段是聲明了NOT NULL的,就是不能為NULL,其他4個(gè)字段都可能是NULL的。
那么現(xiàn)在我們來假設(shè)這個(gè)表里有如下一行數(shù)據(jù),現(xiàn)在來看看,他在磁盤上是怎么來存儲(chǔ)的:“jack NULL m NULL xx_school”,他的5個(gè)字段里有兩個(gè)字段都是NULL
3、結(jié)合小小案例來思考一行數(shù)據(jù)的磁盤存儲(chǔ)格式
接著我們來思考上面那個(gè)表里的那行案例數(shù)據(jù),在磁盤上應(yīng)該如何存儲(chǔ)呢,因?yàn)樗卸鄠€(gè)變長字段,還有多個(gè)字段允許為NULL。首先我們先回顧一下,一行數(shù)據(jù)在磁盤上的存儲(chǔ)格式應(yīng)該是下面這樣的:
變長字段長度列表 NULL值列表 頭信息 column1=value1 column2=value2 ... columnN=valueN
所以先看變長字段長度列表應(yīng)該放什么東西,他一共有4個(gè)變長字段,那么按照我們上次說的,是不是應(yīng)該按照逆序的順序,先放school字段的長度,再放job、address、name幾個(gè)字段的值長度?
說起來是這樣,但是其實(shí)這里要區(qū)分一個(gè)問題,那就是如果這個(gè)變長字段的值是NULL,就不用在變長字段長度列表里存放他的值長度了,所以在上面那行數(shù)據(jù)中,只有name和school兩個(gè)變長字段是有值的,把他們的長度按照逆序放在變長字段長度列表中就可以了,如下所示:
0x09 0x04 NULL值列表 頭信息 column1=value1 column2=value2 ... columnN=valueN
接著來看NULL值列表,這個(gè)NULL值列表是這樣存放的,你所有允許值為NULL的字段,注意,是允許值為NULL,不是說一定值就是NULL了,只要是允許你為NULL的字段,在這里每個(gè)字段都有一個(gè)二進(jìn)制bit位的值,如果bit值是1說明是NULL,如果bit值是0說明不是NULL。
比如上面4個(gè)字段都允許為NULL,每個(gè)人都會(huì)有一個(gè)bit位,這一行數(shù)據(jù)的值是“jack NULL m NULL xx_school”,然后其中2個(gè)字段是null,2個(gè)字段不是null,所以4個(gè)bit位應(yīng)該是:1010
但是實(shí)際放在NULL值列表的時(shí)候,他是按逆序放的,所以在NULL值列表里,放的是:0101,整體這一行數(shù)據(jù)看著是下面這樣的
0x09 0x04 0101 頭信息 column1=value1 column2=value2 ... columnN=valueN
另外就是他實(shí)際NULL值列表存放的時(shí)候,不會(huì)說僅僅是4個(gè)bit位,他一般起碼是8個(gè)bit位的倍數(shù),如果不足8個(gè)bit位就高位補(bǔ)0,所以實(shí)際存放看起來是如下的:
0x09 0x04 00000101 頭信息 column1=value1 column2=value2 ... columnN=valueN
4、磁盤上的一行數(shù)據(jù)到底如何讀取出來的?
我們結(jié)合上面的磁盤上的數(shù)據(jù)存儲(chǔ)格式來思考一下,一行數(shù)據(jù)到底是如何讀取出來的呢?
再看上面的磁盤數(shù)據(jù)存儲(chǔ)格式:
0x09 0x04 00000101 頭信息 column1=value1 column2=value2 ... columnN=valueN
首先他必然要把變長字段長度列表和NULL值列表讀取出來,通過綜合分析一下,就知道有幾個(gè)變長字段,哪幾個(gè)變長字段是NULL,因?yàn)镹ULL值列表里誰是NULL誰不是NULL都一清二楚。
此時(shí)就可以從變長字段長度列表中解析出來不為NULL的變長字段的值長度,然后也知道哪幾個(gè)字段是NULL的,此時(shí)根據(jù)這些信息,就可以從實(shí)際的列值存儲(chǔ)區(qū)域里,把你每個(gè)字段的值讀取出來了。
如果是變長字段的值,就按照他的值長度來讀取,如果是NULL,就知道他是個(gè)NULL,沒有值存儲(chǔ),如果是定長字段,就按照定長長度來讀取,這樣就可以完美的把你一行數(shù)據(jù)的值都讀取出來了!
5、今日思考題
昨天讓大家思考,為什么數(shù)據(jù)要按照這種緊湊的格式來在磁盤里存儲(chǔ),今天我們不公布答案,再次問大家一個(gè)問題,為什么NULL值列表要按照二進(jìn)制bit位的方式來存儲(chǔ)?
他跟直接用NULL字符串的方式來存儲(chǔ),會(huì)有多少存儲(chǔ)空間的差距呢?
希望大家思考一下這個(gè)問題,然后在評論區(qū)發(fā)表你的思考,和大家一起交流,答案我們后面會(huì)公布。
End
專欄版權(quán)歸公眾號(hào)儒猿技術(shù)窩所有
未經(jīng)許可不得傳播,如有侵權(quán)將追究法律責(zé)任