面试官问,为什么建议MySQL列属性尽量用 NOT NULL ?
點(diǎn)擊上方“朱小廝的博客”,選擇“設(shè)為星標(biāo)”
回復(fù)”1024“獲取獨(dú)家整理的學(xué)習(xí)資料
寫(xiě)這篇文章,來(lái)自一個(gè)小伙伴的提問(wèn),他在二面的過(guò)程中被問(wèn)到,由于他簡(jiǎn)歷中寫(xiě)道有 MySQL 調(diào)優(yōu)經(jīng)驗(yàn),但這個(gè)問(wèn)題沒(méi)有回答好,二面被刷了。
其實(shí)我們剛學(xué)習(xí) C 語(yǔ)言的時(shí)候,就接觸過(guò) NULL,比如下面這句代碼。
int *p = NULL;
它實(shí)際上表示將指針指向一塊不被使用的內(nèi)存地址,一般會(huì)在宏中定義好。
那么我們常用的 Java 語(yǔ)言,同樣也用到 null,表示一個(gè)空引用,如果你不小心引用了,那么就會(huì)拋出 NullPointerException,就像昨天 Reddit 上面很火的一張圖。
其實(shí)很早之前 guava 就提供了 Optional 容器類(lèi)來(lái)處理 null,其目的便是避免猝不及防的空指針。后來(lái) java8 直接引入了 Optional,功能一樣,用法上稍稍有點(diǎn)變化。其實(shí)還有很多開(kāi)源框架,比如 Spring,common lang3等,也提供了處理空的工具類(lèi),如。
StringUtils.isBlank();? ?
CollectionUtils.isEmpty();
那么在 MySQL 中,NULL 表示不知道的數(shù)據(jù)。
我們?cè)谠O(shè)計(jì)表的時(shí)候,經(jīng)常會(huì)有老司機(jī)這么告訴我們。
字段盡可能用NOT NULL,而不是NULL,除非特殊情況。
這句話(huà)到底有沒(méi)有錯(cuò)?
可以負(fù)責(zé)任的告訴你這句話(huà)沒(méi)有錯(cuò),也不是以訛傳訛,這句話(huà)首次出現(xiàn)在 MySQL 官網(wǎng)。
如果你讀過(guò)《高性能 MySQL》這本書(shū),你應(yīng)該會(huì)看到這么一段,在 4.1 節(jié)提到。
由此看來(lái),把 NULL 改成 NOT NULL 對(duì)索引的性能并沒(méi)有明顯的提升。避免使用 NULL 的目的,是便于代碼的可讀性和可維護(hù)性。同時(shí)也便于避免下文即將出現(xiàn)的一些稀奇古怪的錯(cuò)誤。
好了,下面咱們通過(guò)實(shí)驗(yàn)來(lái)看看,使用 NULL 會(huì)出現(xiàn)那些稀奇古怪的錯(cuò)誤呢?
跟我一樣在本地建兩個(gè)表 t1,t2;其中一個(gè)表 name 字段允許為空,另一個(gè)表 name 字段不允許為空,分別對(duì) name 字段建立索引,SQL 語(yǔ)句如下
1、NOT IN、!= 等負(fù)向條件查詢(xún)?cè)谟?NULL 值的情況下返回非空行的結(jié)果集
比如上例中的 t2,我執(zhí)行如下 SQL 語(yǔ)句
SELECT * from t2 where name != '張三'
你本打算返回 id 為 2 的那行數(shù)據(jù),然而什么都沒(méi)有。
又比如這條 SQL 語(yǔ)句
select * from t2 where name not in (select name from t2 where id!=1)
也返回了空結(jié)果集。
2、使用 concat 函數(shù)拼接時(shí),首先要對(duì)各個(gè)字段進(jìn)行非 NULL 判斷,否則只要任何一個(gè)字段為空都會(huì)造成拼接的結(jié)果為 NULL
比如下面這條 SQL 語(yǔ)句
SELECT CONCAT("1",NULL)
3、當(dāng)用count函數(shù)進(jìn)行統(tǒng)計(jì)時(shí),NULL 列不會(huì)計(jì)入統(tǒng)計(jì)
SELECT count(name) from t2
4、查詢(xún)空行數(shù)據(jù),用 is NULL
SELECT * FROM t2 where name is NULL
5、NULL 列需要更多的存儲(chǔ)空間,一般需要一個(gè)額外的字節(jié)作為判斷是否為 NULL 的標(biāo)志位。
如果你仔細(xì)觀察 t1 和 t2 表的 key_len,會(huì)發(fā)現(xiàn) t2 比 t1 多了一個(gè)字節(jié)。
explain SELECT * from t2 where name = '張三'
explain SELECT * from t1 where name = '張三'
key_len 的長(zhǎng)度一般跟這三個(gè)因素有關(guān),分別是數(shù)據(jù)類(lèi)型,字符編碼,是否為 NULL。
因此,t2 比 t1 多出的這一個(gè)字節(jié),用于作為判斷是否為 NULL 的標(biāo)志位了。
馬蛋,原來(lái)一切都在書(shū)中。如果面試的哪位同學(xué)多讀幾篇《高性能 MySQL》這本書(shū),那個(gè)崗位就是他的了,但沒(méi)有那么多如果...
在此,建議大家多看官方文檔,多讀點(diǎn)好書(shū),多關(guān)注一些良心的原創(chuàng)技術(shù)自媒體,不要看那些無(wú)憑無(wú)據(jù)的文章,反而會(huì)以訛傳訛,貽害無(wú)窮。
想知道更多?掃描下面的二維碼關(guān)注我
相關(guān)推薦:
《科普 | 明星公司之Netflix》
《看我如何作死 | 將CPU、IO打爆》
《看我如何作死 | 網(wǎng)絡(luò)延遲、丟包、中斷一個(gè)都沒(méi)落下》
《7102-2019年技術(shù)文全套整理,建議收藏》
《看我如何假死!》
《總結(jié)緩存使用過(guò)程中的幾種策略以及優(yōu)缺點(diǎn)組合分析》
加技術(shù)群入口(備注:技術(shù)):>>>Learn More<<
免費(fèi)資料入口(備注:1024):>>>Learn More<<
免費(fèi)星球入口(有需要的+):
點(diǎn)個(gè)"在看"唄^_^
總結(jié)
以上是生活随笔為你收集整理的面试官问,为什么建议MySQL列属性尽量用 NOT NULL ?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 秒懂 QPS、TPS、PV、UV、GMV
- 下一篇: 加入知识星球(永久免费)