偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

MySQL 的 NULL 值是怎么存放的?

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

InnoDB頁

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

我們知道讀寫磁盤是很慢的。當(dāng)我們想從表里獲取數(shù)據(jù)的時(shí)候,InnoDB會(huì)一條一條的從磁盤中讀出來嗎?不會(huì)的!因?yàn)槟菢犹恕K扇〉姆绞绞牵簩?shù)據(jù)劃分為若干頁,以頁做為磁盤和內(nèi)存交互的基本單位。InnoDB中頁的大小一般為16KB。

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

InnoDB 行格式

行格式有哪些

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

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

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

create table 'table info ..' row_format = '行格式名稱'
alter table 'table name' row_format = '行格式名稱'
  • Redundant:是很古老的行格式了, MySQL 5.0 版本之前用的行格式,現(xiàn)在基本沒人用了。
  • Compact:由于 Redundant 不是一種緊湊的行格式,所以 MySQL 5.0 之后引入了 Compact 行記錄存儲(chǔ)方式,Compact 是一種緊湊的行格式,設(shè)計(jì)的初衷就是為了讓一個(gè)數(shù)據(jù)頁中可以存放更多的行記錄,從 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)在基本沒人用了,重點(diǎn)介紹 Compact 行格式,因?yàn)?Dynamic 和 Compressed 這兩個(gè)行格式跟 Compact 非常像。

Compact 格式

話不多說,直接看圖

記錄額外的信息

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

變長字段長度列表

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

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

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

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

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;

我們插入三條記錄

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

先來看第一條記錄:

  • 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 列不是變長字段,這里不用管。

再來看第二條

  • 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)一管理起來,存儲(chǔ)到 NULL 值列表中.

處理過程:

  • 首先統(tǒng)計(jì)表中允許存儲(chǔ) NULL 的列有哪些,主鍵列以及使用 NOT NULL 修飾的列都是不可以存儲(chǔ) NULL 值的,所以在統(tǒng)計(jì)的時(shí)候不會(huì)把這些列算進(jìn)去。
  • 如果表中沒有允許存儲(chǔ) NULL 的列,則 NULL 值列表也就不存在了,否則將每個(gè)允許存儲(chǔ) NULL 的列對應(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。

先來看第一條記錄

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

第二條記錄

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

第三條記錄

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

記錄頭信息

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

  • deleted_flag :標(biāo)識(shí)此條數(shù)據(jù)是否被刪除。從這里可以知道,我們執(zhí)行 detele 刪除記錄的時(shí)候,并不會(huì)真正的刪除記錄,只是將這個(gè)記錄的 delete_mask 標(biāo)記為 1。
  • next_record:下一條記錄的位置。所以我們可以知道,記錄與記錄之間是通過鏈表組織的。在前面我也提到了,指向的是下一條記錄的「記錄頭信息」和「真實(shí)數(shù)據(jù)」之間的位置,這樣的好處是向左讀就是記錄頭信息,向右讀就是真實(shí)數(shù)據(jù),比較方便。
  • record_type:表示當(dāng)前記錄的類型,0表示普通記錄,1表示B+樹非葉子節(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í)候沒有指定主鍵,也沒有唯一約束的列,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ī)制就是依賴 trx_id 和 roll_pointer 來實(shí)現(xiàn)的。

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

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

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

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

總結(jié)

MySQL 的 NULL 值是怎么存放的?

MySQL 的 Compact 行格式中會(huì)用「NULL值列表」來標(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ù)頁存不了一條記錄,InnoDB 存儲(chǔ)引擎會(huì)自動(dòng)將溢出的數(shù)據(jù)存放到「溢出頁」中。

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


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

2010-05-31 15:23:02

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

2010-09-28 11:48:36

SQL NULL值

2025-06-04 02:55:00

MySQLNULL類型

2024-08-09 11:52:18

2021-11-11 13:05:25

MySQLINSERT

2015-07-20 17:05:38

SQL ServerNULL值

2024-03-15 08:06:58

MySQLJOIN命令

2022-09-13 08:33:05

SQLNULL三值邏輯

2020-07-09 10:15:55

空值Bug語言

2011-03-11 09:53:46

FacebookMySQL

2021-07-26 10:32:54

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

2019-05-28 13:50:27

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

2024-12-16 08:20:00

2019-11-15 18:00:18

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

2018-02-06 08:32:09

MySQLNull程序員

2018-01-29 09:21:41

TTL值域名應(yīng)用

2019-07-05 07:50:52

數(shù)據(jù)庫空值查詢

2022-07-03 16:26:43

比特幣貨幣加密貨幣

2020-01-15 15:29:52

InnoDB數(shù)據(jù)硬盤

2022-04-01 07:14:13

模塊Pythonimport
點(diǎn)贊
收藏

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