自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL 的 NULL 值是怎么存放的?

數(shù)據(jù)庫(kù) MySQL
InnoDB是一個(gè)將數(shù)據(jù)存儲(chǔ)到磁盤(pán)上的存儲(chǔ)引擎,所以就算我們關(guān)閉、重啟服務(wù)器,數(shù)據(jù)還是存在的。而在真正處理數(shù)據(jù)的時(shí)候是在內(nèi)存中進(jìn)行的,所以需要把磁盤(pán)中的內(nèi)容加載到內(nèi)存中。

InnoDB頁(yè)

InnoDB是一個(gè)將數(shù)據(jù)存儲(chǔ)到磁盤(pán)上的存儲(chǔ)引擎,所以就算我們關(guān)閉、重啟服務(wù)器,數(shù)據(jù)還是存在的。而在真正處理數(shù)據(jù)的時(shí)候是在內(nèi)存中進(jìn)行的,所以需要把磁盤(pán)中的內(nèi)容加載到內(nèi)存中。

我們知道讀寫(xiě)磁盤(pán)是很慢的。當(dāng)我們想從表里獲取數(shù)據(jù)的時(shí)候,InnoDB會(huì)一條一條的從磁盤(pán)中讀出來(lái)嗎?不會(huì)的!因?yàn)槟菢犹?。它采取的方式是:將?shù)據(jù)劃分為若干頁(yè),以頁(yè)做為磁盤(pán)和內(nèi)存交互的基本單位。InnoDB中頁(yè)的大小一般為16KB。

在服務(wù)器運(yùn)行的過(guò)程中不可以修改頁(yè)的大小,只能在初始化數(shù)據(jù)目錄的時(shí)候指定。

InnoDB 行格式

行格式有哪些

行格式(row_format):一條數(shù)據(jù)記錄在磁盤(pán)上的存儲(chǔ)結(jié)構(gòu)。

InnoDB 提供了 4 種行格式,分別是 Redundant、Compact、Dynamic和 Compressed 行格式。

我們可以在創(chuàng)建表或者修改表的語(yǔ)句中指定所使用的行格式

create table 'table info ..' row_format = '行格式名稱(chēng)'
alter table 'table name' row_format = '行格式名稱(chēng)'
  • Redundant:是很古老的行格式了, MySQL 5.0 版本之前用的行格式,現(xiàn)在基本沒(méi)人用了。
  • Compact:由于 Redundant 不是一種緊湊的行格式,所以 MySQL 5.0 之后引入了 Compact 行記錄存儲(chǔ)方式,Compact 是一種緊湊的行格式,設(shè)計(jì)的初衷就是為了讓一個(gè)數(shù)據(jù)頁(yè)中可以存放更多的行記錄,從 MySQL 5.1 版本之后,行格式默認(rèn)設(shè)置成 Compact。
  • Dynamic 和 Compressed 兩個(gè)都是緊湊的行格式,它們的行格式都和 Compact 差不多,因?yàn)槎际腔?Compact 改進(jìn)一點(diǎn)東西。從 MySQL5.7 版本之后,默認(rèn)使用 Dynamic 行格式。

Redundant 行格式因?yàn)楝F(xiàn)在基本沒(méi)人用了,重點(diǎn)介紹 Compact 行格式,因?yàn)?Dynamic 和 Compressed 這兩個(gè)行格式跟 Compact 非常像。

Compact 格式

話(huà)不多說(shuō),直接看圖

記錄額外的信息

這部分信息是服務(wù)器為了更好的管理記錄而不得不額外添加的一些信息,這些額外信息分為三個(gè)部分,分別是:變長(zhǎng)字段長(zhǎng)度列表、NULL值列表和記錄頭信息。

變長(zhǎng)字段長(zhǎng)度列表

在mysql中有一些變長(zhǎng)的數(shù)據(jù)類(lèi)型,比如varchar( )、varbinary( )、text類(lèi)型、blob類(lèi)型,我們把使用這個(gè)變長(zhǎng)類(lèi)型的列成為變長(zhǎng)字段。

所以,在存儲(chǔ)數(shù)據(jù)的時(shí)候,也要把數(shù)據(jù)占用的大小存起來(lái),存到「變長(zhǎng)字段長(zhǎng)度列表」里面,讀取數(shù)據(jù)的時(shí)候才能根據(jù)這個(gè)「變長(zhǎng)字段長(zhǎng)度列表」去讀取對(duì)應(yīng)長(zhǎng)度的數(shù)據(jù)。

這些變長(zhǎng)字段的真實(shí)數(shù)據(jù)占用的字節(jié)數(shù)會(huì)按照列的順序逆序存放(后面會(huì)說(shuō)為什么要這么設(shè)計(jì))。

為了展示具體是怎么保存「變長(zhǎng)字段的真實(shí)數(shù)據(jù)占用的字節(jié)數(shù)」,我們先創(chuàng)建這樣一張表,字符集是 ascii(所以每一個(gè)字符占用的 1 字節(jié)),行格式是 Compact,student 表中 name 和 dream_school 字段是變長(zhǎng)字段:

CREATE TABLE `student` (
  `id` int(11) NOT NULL,
  `name` VARCHAR(20) DEFAULT NULL,
  `dream_school` VARCHAR(20) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB DEFAULT CHARACTER SET = ascii ROW_FORMAT = COMPACT;

我們插入三條記錄

我們看看這三條記錄的行格式中的 變長(zhǎng)字段長(zhǎng)度列表 是怎樣存儲(chǔ)的。

先來(lái)看第一條記錄:

  • name 列的值為 1,真實(shí)數(shù)據(jù)占用的字節(jié)數(shù)是 1 字節(jié),十六進(jìn)制 0x01;
  • dream_school 列的值為 qinghua,真實(shí)數(shù)據(jù)占用的字節(jié)數(shù)是 7 字節(jié),十六進(jìn)制 0x07;
  • age 列和 id 列不是變長(zhǎng)字段,這里不用管。

再來(lái)看第二條

  • name 列的值為 1,真實(shí)數(shù)據(jù)占用的字節(jié)數(shù)是 2 字節(jié),十六進(jìn)制 0x02;
  • dream_school 列的值為 beida,真實(shí)數(shù)據(jù)占用的字節(jié)數(shù)是 5 字節(jié),十六進(jìn)制 0x05;

第三條記錄

第三條記錄 dream_school 列的值是 NULL,NULL 是不會(huì)存放在行格式中記錄的真實(shí)數(shù)據(jù)部分里的。

null值列表一條記錄中的某些列可能存儲(chǔ) NULL 值,如果把這些 NULL 值都放到記錄的 真實(shí)數(shù)據(jù)中存儲(chǔ)會(huì)很占地方,所以 OMPACT 行格式把一條記錄中值為 NULL 的列統(tǒng)一管理起來(lái),存儲(chǔ)到 NULL 值列表中.

處理過(guò)程:

  • 首先統(tǒng)計(jì)表中允許存儲(chǔ) NULL 的列有哪些,主鍵列以及使用 NOT NULL 修飾的列都是不可以存儲(chǔ) NULL 值的,所以在統(tǒng)計(jì)的時(shí)候不會(huì)把這些列算進(jìn)去。
  • 如果表中沒(méi)有允許存儲(chǔ) NULL 的列,則 NULL 值列表也就不存在了,否則將每個(gè)允許存儲(chǔ) NULL 的列對(duì)應(yīng)一個(gè) 進(jìn)制位,二進(jìn)制位按照列的順序逆序排列。二進(jìn)制位表示的意義如下
  • 進(jìn)制位的值為1時(shí),代表該列的值為NULL。
  • 迸制位的值為0時(shí),代表該列的值不為NULL。
  • 另外,NULL 值列表必須用整數(shù)個(gè)字節(jié)的位表示(1字節(jié)8位),如果使用的二進(jìn)制位個(gè)數(shù)不足整數(shù)個(gè)字節(jié),則在字節(jié)的高位補(bǔ) 0。

先來(lái)看第一條記錄

第一條記錄所有列都有值,不存在 NULL 值,用二進(jìn)制來(lái)表示是這樣的:

第二條記錄

接下來(lái)看第二條記錄,第二條記錄 age 列是 NULL 值,用二進(jìn)制來(lái)表示是這樣的:

第三條記錄

第三條記錄 dream_school 列 和 age 列是 NULL 值,用二進(jìn)制來(lái)表示是這樣的:

記錄頭信息

記錄頭信息由固定5個(gè)字節(jié)組成,用于描述記錄的一些屬性,這里的屬性比較多,我們就列舉幾個(gè)相對(duì)來(lái)說(shuō)重要點(diǎn)的。

  • deleted_flag :標(biāo)識(shí)此條數(shù)據(jù)是否被刪除。從這里可以知道,我們執(zhí)行 detele 刪除記錄的時(shí)候,并不會(huì)真正的刪除記錄,只是將這個(gè)記錄的 delete_mask 標(biāo)記為 1。
  • next_record:下一條記錄的位置。所以我們可以知道,記錄與記錄之間是通過(guò)鏈表組織的。在前面我也提到了,指向的是下一條記錄的「記錄頭信息」和「真實(shí)數(shù)據(jù)」之間的位置,這樣的好處是向左讀就是記錄頭信息,向右讀就是真實(shí)數(shù)據(jù),比較方便。
  • record_type:表示當(dāng)前記錄的類(lèi)型,0表示普通記錄,1表示B+樹(shù)非葉子節(jié)點(diǎn)記錄,2表示最小記錄,3表示最大記錄

記錄真實(shí)數(shù)據(jù)

記錄真實(shí)數(shù)據(jù)除了記錄我們自定義的列的數(shù)據(jù)外,Mysql還會(huì)為每個(gè)記錄默認(rèn)添加一些列(隱藏列)

  • row_id:當(dāng)我們創(chuàng)建表的時(shí)候沒(méi)有指定主鍵,也沒(méi)有唯一約束的列,innodb 就會(huì)自動(dòng)的為這些記錄添加row_id隱藏字段,占用6個(gè)字節(jié)。不是必須會(huì)有的。
  • trx_id:事務(wù)ID,這個(gè)列是必須的,占用6個(gè)字節(jié)。表示數(shù)據(jù)是有哪個(gè)事務(wù)生產(chǎn)的。
  • roll_pointer:回滾指針,表示當(dāng)前記錄上一個(gè)版本的指針,這個(gè)列也是必需的,占用 7 個(gè)字節(jié)。

MVCC機(jī)制就是依賴(lài) trx_id 和 roll_pointer 來(lái)實(shí)現(xiàn)的。

行溢出后,MySQL 是怎么處理的?

MySQL 中磁盤(pán)和內(nèi)存交互的基本單位是頁(yè),一個(gè)頁(yè)的大小一般是 16KB,也就是 16384字節(jié),而一個(gè) varchar(n) 類(lèi)型的列最多可以存儲(chǔ) 65532字節(jié),一些大對(duì)象如 TEXT、BLOB 可能存儲(chǔ)更多的數(shù)據(jù),這時(shí)一個(gè)頁(yè)可能就存不了一條記錄。這個(gè)時(shí)候就會(huì)發(fā)生行溢出,多的數(shù)據(jù)就會(huì)存到另外的「溢出頁(yè)」中。

如果一個(gè)數(shù)據(jù)頁(yè)存不了一條記錄,InnoDB 存儲(chǔ)引擎會(huì)自動(dòng)將溢出的數(shù)據(jù)存放到「溢出頁(yè)」中。在一般情況下,InnoDB 的數(shù)據(jù)都是存放在 「數(shù)據(jù)頁(yè)」中。但是當(dāng)發(fā)生行溢出時(shí),溢出的數(shù)據(jù)會(huì)存放到「溢出頁(yè)」中。

當(dāng)發(fā)生行溢出時(shí),在記錄的真實(shí)數(shù)據(jù)處只會(huì)保存該列的一部分?jǐn)?shù)據(jù),而把剩余的數(shù)據(jù)放在「溢出頁(yè)」中,然后真實(shí)數(shù)據(jù)處用 20 字節(jié)存儲(chǔ)指向溢出頁(yè)的地址,從而可以找到剩余數(shù)據(jù)所在的頁(yè)。大致如下圖所示。

總結(jié)

MySQL 的 NULL 值是怎么存放的?

MySQL 的 Compact 行格式中會(huì)用「NULL值列表」來(lái)標(biāo)記值為 NULL 的列,NULL 值并不會(huì)存儲(chǔ)在行格式中的真實(shí)數(shù)據(jù)部分。

NULL值列表會(huì)占用 1 字節(jié)空間,當(dāng)表中所有字段都定義成 NOT NULL,行格式中就不會(huì)有 NULL值列表,這樣可節(jié)省 1 字節(jié)的空間。

行溢出后,MySQL 是怎么處理的?

如果一個(gè)數(shù)據(jù)頁(yè)存不了一條記錄,InnoDB 存儲(chǔ)引擎會(huì)自動(dòng)將溢出的數(shù)據(jù)存放到「溢出頁(yè)」中。

Compact 行格式針對(duì)行溢出的處理是這樣的:當(dāng)發(fā)生行溢出時(shí),在記錄的真實(shí)數(shù)據(jù)處只會(huì)保存該列的一部分?jǐn)?shù)據(jù),而把剩余的數(shù)據(jù)放在「溢出頁(yè)」中,然后真實(shí)數(shù)據(jù)處用 20 字節(jié)存儲(chǔ)指向溢出頁(yè)的地址,從而可以找到剩余數(shù)據(jù)所在的頁(yè)。


責(zé)任編輯:華軒 來(lái)源: 今日頭條
相關(guān)推薦

2010-05-31 15:23:02

MySQL數(shù)據(jù)庫(kù)NUL

2010-09-28 11:48:36

SQL NULL值

2021-11-11 13:05:25

MySQLINSERT

2024-08-09 11:52:18

2015-07-20 17:05:38

SQL ServerNULL值

2020-07-09 10:15:55

空值Bug語(yǔ)言

2022-09-13 08:33:05

SQLNULL三值邏輯

2024-03-15 08:06:58

MySQLJOIN命令

2011-03-11 09:53:46

FacebookMySQL

2021-07-26 10:32:54

MySQL數(shù)據(jù)庫(kù)存儲(chǔ)

2024-12-16 08:20:00

2019-05-28 13:50:27

MySQL幻讀數(shù)據(jù)庫(kù)

2018-02-06 08:32:09

MySQLNull程序員

2019-11-15 18:00:18

MySQLSQL數(shù)據(jù)庫(kù)

2019-07-05 07:50:52

數(shù)據(jù)庫(kù)空值查詢(xún)

2018-01-29 09:21:41

TTL值域名應(yīng)用

2010-11-26 13:40:58

MySQL空字符串

2020-01-15 15:29:52

InnoDB數(shù)據(jù)硬盤(pán)

2020-08-18 22:20:49

vue.jsnullclass

2025-02-11 00:11:00

NULL運(yùn)算篩選
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)