由null出發(fā)-看看為何mysql這么排斥null

前言

在表結(jié)構(gòu)設(shè)計(jì)時(shí)我們經(jīng)常會(huì)面對(duì)是否要加空值約束墨叛、默認(rèn)值處理等問題石窑,當(dāng)向前人經(jīng)驗(yàn)中檢索時(shí)炫欺,經(jīng)常會(huì)看到不建議為null懊纳,強(qiáng)刷面經(jīng)時(shí)not null也經(jīng)常被歸結(jié)到優(yōu)化建議當(dāng)中去揉抵,今天就來看一下為何?
通常來說嗤疯,null表示虛無&不確定冤今,在不同的實(shí)現(xiàn)中對(duì)null的定義相似。最早在Codd提出關(guān)系模型的最早的paper里茂缚,就引入了NULL戏罢。
先看不同語(yǔ)言對(duì)于null的處理:

c++的NULL

c++中NULL是一個(gè)宏,是一個(gè)空指針常量脚囊,如果將NULL擴(kuò)展為常數(shù)龟糕,那么這個(gè)數(shù)是0,類型為int悔耘,也就是說常數(shù)0既是整型常量讲岁,也是空指針常量(cpp 11中引入了nullptr作為空指針常量,解決二義性)衬以。

Java的null

Java中的null是一個(gè)關(guān)鍵字缓艳,通常指的是非基礎(chǔ)類型變量的引用指向一個(gè)“空”,可以理解為引用對(duì)象為不確定泄鹏,Java是一種基于copy傳遞的基礎(chǔ)類型+引用類型數(shù)據(jù)構(gòu)成的對(duì)象體系郎任,Java內(nèi)存管理中使用句柄來操控對(duì)象,而null表示句柄所在的內(nèi)存地址上沒有存儲(chǔ)任何真實(shí)對(duì)象的地址备籽。

go的nil

go中沒有null這個(gè)關(guān)鍵字(任何類型都會(huì)零值處理),但是有一個(gè)類似的nil(注意不是關(guān)鍵字),跟null的定位類似但不是完全相同车猬,是一個(gè)預(yù)先定義的標(biāo)識(shí)符霉猛,通常用于指針類型、map珠闰、slice惜浅、function、channel伏嗜、interface等類型的零值定義坛悉,是一個(gè)沒有默認(rèn)類型的空值,標(biāo)示的并非不確定性承绸,而是可以明確代表各種不同內(nèi)存布局的類型的零值裸影。
比如說:

fmt.Println( (interface{})(nil) == (*int)(nil) ) 
// print:false

//下面這樣聲明零值后是 零值間是無法比較的
var _ = ([]int)(nil) == ([]int)(nil)
var _ = (map[string]int)(nil) == (map[string]int)(nil)
var _ = (func())(nil) == (func())(nil)

然后來看存儲(chǔ)中對(duì)null的定義:

redis中的空值

redis中操作時(shí)都是針對(duì)明確的值的,不會(huì)出現(xiàn)像是不確定這樣的定義军熏,通常來說轩猩,所以在操作redis時(shí)是沒有對(duì)null的數(shù)據(jù)定義的,但是會(huì)有nil這樣的零值存在荡澎,跟go處理方式比較像均践,代表n個(gè)結(jié)構(gòu)的零值,一些語(yǔ)言對(duì)于nil return這種情況有時(shí)候會(huì)變成一種null來處理摩幔,因?yàn)閷?duì)于client來說彤委,這就是個(gè)不確定的返回或者空值。

127.0.0.1:6379> get B
(nil)

說到redis了或衡,也順道看下lua對(duì)于空返回的處理焦影,容易寫出bug來,簡(jiǎn)單記錄了下薇宠,與本章主題無關(guān)偷办。官方文檔中的:
A non-nil Redis "bulk reply" results in a Lua string as the return value.
A nil bulk reply results in a ngx.null return value

mysql的空值定義

看到各種語(yǔ)言、工具中對(duì)null澄港、nil等關(guān)鍵詞的使用椒涯,不難發(fā)現(xiàn) null代表的是一種內(nèi)存存儲(chǔ)的不確定性,nil代表的通常是一種約定的零值回梧。
mysql中也是如此废岂,null代表的是一種不確定性,所以通常用is null 或者not null來判定一個(gè)實(shí)例數(shù)據(jù)是否為不確定的狱意,而不是直接==來進(jìn)行值比較湖苞。
官方手冊(cè)中中的定義:
The NULL value means “no data.” NULL can be written in any lettercase
也就產(chǎn)生了下面的關(guān)系操作符:
IS NULL\IS NOT NULL:能正常比較
<=>:結(jié)果都是false
mysql 這樣對(duì)null的定義導(dǎo)致了一些問題:
1、誤導(dǎo)性&sql操作時(shí)的疏忽

select A from t_xx where B not null or B = 2\G #正常操作
select A from t_xx where B = null or B = 2\G # B = null條件異常
select * from tableA where xxx not in(1, 2, null)\G #返回永遠(yuǎn)為空
select count(*) from tableA\G #null不參與統(tǒng)計(jì)

2详囤、另外财骨,null值在timestamp類型下容易出問題镐作,特別是沒有啟用參數(shù)explicit_defaults_for_timestamp

mysql null的空間表現(xiàn)

null在mysql中是一種特殊的“占位符”,用來表示不確定性隆箩,但是實(shí)際上它也是需要占用一部分內(nèi)存空間的该贾,比不是所想的會(huì)省內(nèi)存。
null的長(zhǎng)度是null,Compact Row Format前提下捌臊,每個(gè)行記錄都會(huì)有一個(gè)Bit vector來記錄行中出現(xiàn)NULL的字段杨蛋,長(zhǎng)度為 N / 8 向上取整,其中 N為值NULL的字段數(shù)理澎。

select length(''), length(null), length(0), length('0');
 +------------+--------------+-----------+-------------+
 | length('') | length(null) | length(0) | length('0') |
 +------------+--------------+-----------+-------------+
 |          0 |         NULL |         1 |           1 |
 +------------+--------------+-----------+-------------+

對(duì)于變長(zhǎng)字段是可以起到一定的省空間的作用逞力,對(duì)于int/char這些是毫無作用的,并且需要一個(gè)額外字節(jié)作為判斷是否為null的標(biāo)志位(這個(gè)是問題糠爬,但忽略不計(jì))
某些情況可以省寇荧,但是相對(duì)于它帶來的其他影響,這點(diǎn)優(yōu)勢(shì)啥都不是秩铆,繼續(xù)往下看

mysql null對(duì)索引的影響

Mysql難以優(yōu)化引用可空列查詢砚亭,它會(huì)使索引、索引統(tǒng)計(jì)和值更加復(fù)雜殴玛⊥北欤可空列需要更多的存儲(chǔ)空間,還需要mysql內(nèi)部進(jìn)行特殊處理滚粟⊙罢蹋可空列被索引后,每條記錄都需要一個(gè)額外的字節(jié)凡壤,還能導(dǎo)致MYisam 中固定大小的索引變成可變大小的索引署尤。 --《高性能mysql》
1、雖然mysql會(huì)對(duì)null字段也進(jìn)行索引亚侠,但是只有is null的方式會(huì)使用上索引,所以一旦使用不好曹体,索引就無效了。
2硝烂、如果null列做了唯一索引箕别,那就尷尬了:唯一索引字段允許插入多條null的記錄
3、null一定程度上會(huì)是key_len變長(zhǎng)(key_len 的計(jì)算規(guī)則和三個(gè)因素有關(guān):數(shù)據(jù)類型滞谢、字符編碼串稀、是否為null,上面也提到啦)
4、mysql內(nèi)部會(huì)對(duì)null 做很多特殊邏輯的處理影響性能狮杨。

總結(jié)

1母截、使用上容易出錯(cuò)
2、很容易導(dǎo)致索引不可用或者效率下降
3橄教、很多情況下會(huì)增加存儲(chǔ)
4清寇、提升表的維護(hù)成本
所有使用NULL值的情況喘漏,都可以通過一個(gè)有意義的值的表示,這樣有利于代碼的可讀性和可維護(hù)性颗管。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陷遮,一起剝皮案震驚了整個(gè)濱河市滓走,隨后出現(xiàn)的幾起案子垦江,更是在濱河造成了極大的恐慌,老刑警劉巖搅方,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件比吭,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡姨涡,警方通過查閱死者的電腦和手機(jī)衩藤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涛漂,“玉大人赏表,你說我怎么就攤上這事⌒僬蹋” “怎么了瓢剿?”我有些...
    開封第一講書人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)悠轩。 經(jīng)常有香客問我间狂,道長(zhǎng),這世上最難降的妖魔是什么火架? 我笑而不...
    開封第一講書人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任鉴象,我火速辦了婚禮,結(jié)果婚禮上何鸡,老公的妹妹穿的比我還像新娘纺弊。我一直安慰自己,他們只是感情好骡男,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開白布淆游。 她就那樣靜靜地躺著,像睡著了一般洞翩。 火紅的嫁衣襯著肌膚如雪稽犁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評(píng)論 1 308
  • 那天骚亿,我揣著相機(jī)與錄音已亥,去河邊找鬼。 笑死来屠,一個(gè)胖子當(dāng)著我的面吹牛虑椎,可吹牛的內(nèi)容都是我干的震鹉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼捆姜,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼传趾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起泥技,我...
    開封第一講書人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤浆兰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后珊豹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體簸呈,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年店茶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蜕便。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贩幻,死狀恐怖轿腺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情丛楚,我是刑警寧澤族壳,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站鸯檬,受9級(jí)特大地震影響决侈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喧务,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一赖歌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧功茴,春花似錦庐冯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至玲昧,卻和暖如春栖茉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背孵延。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工吕漂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尘应。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓惶凝,卻偏偏與公主長(zhǎng)得像吼虎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子苍鲜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359