DBA:字段一定要設(shè)置為非空,省空間攀甚!我:你拉倒吧

背景

DBA 又把建表語(yǔ)句打回來(lái)了箩朴,原因是字段可空了!理由是為了省空間!G锒取Uㄅ印!

語(yǔ)句如下:

CREATE TABLE user_info (

id bigint unsigned NOT NULL AUTO_INCREMENT,

user_id int NOT NULL COMMENT '用戶id',

user_name varchar(64) NOT NULL COMMENT '真實(shí)姓名',

email varchar(30) NOT NULL COMMENT '用戶郵箱',

nick_name varchar(45) COMMENT '昵稱',

status tinyint NOT NULL COMMENT '用戶狀態(tài)荚斯,1-正常埠居,2-注銷,3-凍結(jié)',

address varchar(128) COMMENT '家庭住址',

--省略了一些屬性事期,篇幅原因滥壕,這里刪掉了

PRIMARY KEY (id),

KEY idx_user_id (user_id)

) ENGINE=InnoDB COMMENT='用戶基本信息';

用戶可能就是沒(méi)有昵稱啊,設(shè)置為可空兽泣,看起來(lái)也沒(méi)啥問(wèn)題耙镩佟!有沒(méi)有一種被針對(duì)的感覺(jué)

其實(shí)你如果知道每條記錄真正的存儲(chǔ)格式唠倦,你就知道怎么懟他了金踪。

正文

InnoDB 頁(yè)的概念

Page 是 Innodb 存儲(chǔ)的最基本結(jié)構(gòu),也是 Innodb 磁盤管理的最小單位牵敷,與數(shù)據(jù)庫(kù)相關(guān)的所有內(nèi)容都存儲(chǔ)在 Page 結(jié)構(gòu)里。

MySQL 的客戶端和服務(wù)端的交互最小單位也是 Innodb 頁(yè)(默認(rèn)大小為 16K)法希,也就是說(shuō)如果你即使只查詢一條記錄枷餐,一次至少?gòu)拇疟P上讀取 16K 的內(nèi)容到內(nèi)存中。

Innodb 行格式

我們平時(shí)往數(shù)據(jù)庫(kù)插入一條條的記錄苫亦,這些記錄在磁盤上存放格式也是以行記錄的方式的毛肋。

Innodb 存儲(chǔ)引擎目前有四種格式--COMPACT、REDUNDANT屋剑、DYNAMIC润匙、COMPRESSED

從 MySQL5.7 開始,默認(rèn)是 DYNAMIC 方式唉匾,我們用圖片來(lái)看一下 Innodb 行格式大概示意圖孕讳。(這里以 COMPACT為例匠楚,因?yàn)檫@ 2 者基本上是一樣的,只有一些細(xì)微的差別)

記錄額外信息

這里只講變長(zhǎng)屬性長(zhǎng)度列表厂财、NULL 值列表 2 個(gè)部分

1芋簿、變長(zhǎng)屬性長(zhǎng)度列表

常見的關(guān)系型數(shù)據(jù)庫(kù)都支持變長(zhǎng)屬性,比如上面的語(yǔ)句username varchar(64)中璃饱,64 是代表可存儲(chǔ)的最大字符數(shù)与斤,如果某條記錄的名字是“張三”,會(huì)有什么樣的問(wèn)題呢

我們要讓 MySQL 服務(wù)器知道每條記錄的每個(gè)變長(zhǎng)屬性知道實(shí)際長(zhǎng)度是多少荚恶,不然它會(huì)懵

我們來(lái)舉一個(gè)栗子:


上面的記錄 user_name,email,nick_name,address 都是 varchar 類型的撩穿,那么他存儲(chǔ)的記錄格式是什么樣的呢

上圖中的 09、0b谒撼、06食寡、09 分別對(duì)應(yīng) user_name,email,nick_name、address 對(duì)應(yīng)字節(jié)長(zhǎng)度嗤栓,16 進(jìn)制(實(shí)際上無(wú)空格冻河,這里只是為了方便看)。

至于為什么是倒序放的茉帅,不是本文重點(diǎn)叨叙,這里先不做解答

小彩蛋:varchar(M)中的 M 代表能存儲(chǔ)的最大字符數(shù),實(shí)際存儲(chǔ)時(shí)都是按照字節(jié)來(lái)計(jì)算的堪澎,所以一個(gè)字段占用的實(shí)際字節(jié)數(shù)的公式:

RL(存儲(chǔ)屬性最多的字節(jié)數(shù))=M(最多字符數(shù))* W(當(dāng)前字符集下最多需要幾個(gè)字節(jié)表示一個(gè)字符)

所以在編碼是 utf8mb4 的情況下擂错,user_name 最多占用的字節(jié)數(shù)=64 * 4 = 256,所以該屬性需要 2 個(gè)字節(jié)表示長(zhǎng)度

為什么不是 1 個(gè)字節(jié)樱蛤,1 個(gè)字節(jié)不正好是 256 嗎钮呀?因?yàn)榈谝晃皇?b>標(biāo)記位,如果第一位是 0昨凡,表示用 1 個(gè)字節(jié)就可以表示該屬性的長(zhǎng)度爽醋,如果第一位是 1,表示需要用 2 個(gè)字節(jié)表示該屬性的長(zhǎng)度便脊。

但是如果RL大于256蚂四,占用的字節(jié)也是2個(gè),字段屬性值保存一部分或者(數(shù)據(jù)地址)

如果另一條記錄是這樣的:


則對(duì)應(yīng)的行格式如下:

昵稱哪痰、家庭住址為空遂赠,則不在變長(zhǎng)長(zhǎng)度列表中出現(xiàn)。

2晌杰、NULL 值列表

我們?cè)诓迦胍粭l記錄時(shí)跷睦,Innodb 引擎怎么處理

先統(tǒng)計(jì)允許為 NULL 的列有哪些

如果建表語(yǔ)句中,沒(méi)有可空的字段肋演,就沒(méi)有 NULL 值列表抑诸;如果有可空的字段烂琴,那么每個(gè)可空字段對(duì)應(yīng)一個(gè)二進(jìn)制位,1-代表 NULL哼鬓,0-不為 NULL

最小單位需要用字節(jié)來(lái)表示 NULL 值列表监右,如果只有 2 個(gè)可空值,至少也需要 1 個(gè)字節(jié)來(lái)表示异希,高位補(bǔ) 0健盒,如張無(wú)忌對(duì)應(yīng)的 NULL 值列表為 00000011,張三豐對(duì)應(yīng)的 NULL 值列表為 00000000

張三豐對(duì)應(yīng)的記錄行格式(00000000):

張無(wú)忌對(duì)應(yīng)的記錄行格式(00000011):

綜上

如果一張表沒(méi)有可空的字段称簿,比如建表語(yǔ)句如下:

語(yǔ)句如下:

CREATE TABLE user_info (

id bigint unsigned NOT NULL AUTO_INCREMENT,

user_id int NOT NULL COMMENT '用戶id',

user_name varchar(64) NOT NULL COMMENT '真實(shí)姓名',

email varchar(30) NOT NULL COMMENT '用戶郵箱',

nick_name varchar(45) NOT NULL COMMENT '昵稱',

status tinyint NOT NULL COMMENT '用戶狀態(tài)扣癣,1-正常,2-注銷憨降,3-凍結(jié)',

address varchar(128) NOT NULL COMMENT '家庭住址',

--省略了一些屬性父虑,篇幅原因,這里刪掉了

PRIMARY KEY (id),

KEY idx_user_id (user_id)

) ENGINE=InnoDB COMMENT='用戶基本信息';

對(duì)應(yīng)的行結(jié)構(gòu)如下:

沒(méi)有 NULL 值列表哪一項(xiàng)授药,但是雖然 NULL 列表中沒(méi)有了士嚎,變長(zhǎng)列表中會(huì)有,同時(shí)真實(shí)數(shù)據(jù)部分也會(huì)有悔叽,占用的空間更大莱衩,可見為了省空間這種說(shuō)法站不住腳。

總結(jié)

原因到底是為什么呢娇澎?

MySQL 官方有那么一句話:

NULL columns require additional space in the rowto record whether their values are NULL. For MyISAM tables, each NULL columntakes one bit extra, rounded up to the nearest byte.

中文意思是:

Mysql 難以優(yōu)化引用可空列查詢笨蚁,它會(huì)使索引、索引統(tǒng)計(jì)和值更加復(fù)雜趟庄±ㄏ福可空列需要更多的存儲(chǔ)空間,還需要 mysql 內(nèi)部進(jìn)行特殊處理戚啥》艿ィ可空列被索引后,每條記錄都需要一個(gè)額外的字節(jié)猫十,還能導(dǎo)致 MYisam 中固定大小的索引變成可變大小的索引览濒。

照此看來(lái),官方說(shuō)法是其中一點(diǎn)原因炫彩,站在Innodb的行格式上,不見得是省空間的絮短。

作者拙見:

所有使用 NULL 值的情況江兢,都可以通過(guò)一個(gè)有意義的值的表示,這樣有利于代碼的可讀性和可維護(hù)性丁频,并能從約束上增強(qiáng)業(yè)務(wù)數(shù)據(jù)的規(guī)范性杉允。

NULL 值到非 NULL 的更新無(wú)法做到原地更新邑贴,更容易發(fā)生索引分裂,從而影響性能叔磷。

NULL 值在 timestamp 類型下容易出問(wèn)題拢驾,特別是沒(méi)有啟用參數(shù) explicit_defaults_for_timestamp

NOT IN、!= 等負(fù)向條件查詢?cè)谟?NULL 值的情況下返回永遠(yuǎn)為空結(jié)果改基,查詢?nèi)菀壮鲥e(cuò)繁疤,不是自己想要的結(jié)果,甚至可能出現(xiàn)重大損失

首發(fā)自:https://www.kuya123.com/2021/06/mysql-not-null

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末秕狰,一起剝皮案震驚了整個(gè)濱河市稠腊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鸣哀,老刑警劉巖架忌,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異我衬,居然都是意外死亡叹放,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門挠羔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)井仰,“玉大人,你說(shuō)我怎么就攤上這事褥赊「獾担” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵拌喉,是天一觀的道長(zhǎng)速那。 經(jīng)常有香客問(wèn)我,道長(zhǎng)尿背,這世上最難降的妖魔是什么端仰? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮田藐,結(jié)果婚禮上荔烧,老公的妹妹穿的比我還像新娘。我一直安慰自己汽久,他們只是感情好鹤竭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著景醇,像睡著了一般臀稚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上三痰,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天吧寺,我揣著相機(jī)與錄音窜管,去河邊找鬼。 笑死稚机,一個(gè)胖子當(dāng)著我的面吹牛幕帆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赖条,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼失乾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了谋币?” 一聲冷哼從身側(cè)響起仗扬,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蕾额,沒(méi)想到半個(gè)月后呼奢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谍珊,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斤讥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年桑包,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片调炬。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡语盈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缰泡,到底是詐尸還是另有隱情刀荒,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布棘钞,位于F島的核電站缠借,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宜猜。R本人自食惡果不足惜泼返,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望姨拥。 院中可真熱鬧绅喉,春花似錦、人聲如沸叫乌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)憨奸。三九已至革屠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背屠阻。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留额各,地道東北人国觉。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像虾啦,于是被迫代替她去往敵國(guó)和親麻诀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容