最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

為什么mysql字段要使用NOT NULL

 更新時(shí)間:2021年05月13日 10:18:01   作者:艾小仙  
數(shù)據(jù)庫(kù)字段一定要設(shè)置為 not null,不然會(huì)有很大的bug,下面就一起來(lái)介紹一下,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

最近剛?cè)肼毿鹿?,發(fā)現(xiàn)數(shù)據(jù)庫(kù)設(shè)計(jì)有點(diǎn)小問(wèn)題,數(shù)據(jù)庫(kù)字段很多沒有NOT NULL,對(duì)于強(qiáng)迫癥晚期患者來(lái)說(shuō),簡(jiǎn)直難以忍受,因此有了這篇文章。

基于目前大部分的開發(fā)現(xiàn)狀來(lái)說(shuō),我們都會(huì)把字段全部設(shè)置成NOT NULL并且給默認(rèn)值的形式。

  • 通常,對(duì)于默認(rèn)值一般這樣設(shè)置:
  • 整形,我們一般使用0作為默認(rèn)值。
  • 字符串,默認(rèn)空字符串

時(shí)間,可以默認(rèn)1970-01-01 08:00:01,或者默認(rèn)0000-00-00 00:00:00,但是連接參數(shù)要添加zeroDateTimeBehavior=convertToNull,建議的話還是不要用這種默認(rèn)的時(shí)間格式比較好

但是,考慮下原因,為什么要設(shè)置成NOT NULL?

來(lái)自高性能Mysql中有這樣一段話:

盡量避免NULL

很多表都包含可為NULL(空值)的列,即使應(yīng)用程序并不需要保存NULL也是如此,這是因?yàn)榭蔀镹ULL是列的默認(rèn)屬性。通常情況下最好指定列為NOT NULL,除非真的需要存儲(chǔ)NULL值。

如果查詢中包含可為NULL的列,對(duì)MySql來(lái)說(shuō)更難優(yōu)化,因?yàn)榭蔀镹ULL的列使得索引、索引統(tǒng)計(jì)和值比較都更復(fù)雜??蔀镹ULL的列會(huì)使用更多的存儲(chǔ)空間,在MySql里也需要特殊處理。當(dāng)可為NULL的列被索引時(shí),每個(gè)索引記錄需要一個(gè)額外的字節(jié),在MyISAM里甚至還可能導(dǎo)致固定大小的索引(例如只有一個(gè)整數(shù)列的索引)變成可變大小的索引。

通常把可為NULL的列改為NOT NULL帶來(lái)的性能提升比較小,所以(調(diào)優(yōu)時(shí))沒有必要首先在現(xiàn)有schema中查找并修改掉這種情況,除非確定這會(huì)導(dǎo)致問(wèn)題。但是,如果計(jì)劃在列上建索引,就應(yīng)該盡量避免設(shè)計(jì)成可為NULL的列。

當(dāng)然也有例外,例如值得一提的是,InnoDB使用單獨(dú)的位(bit)存儲(chǔ)NULL值,所以對(duì)于稀疏數(shù)據(jù)有很好的空間效率。但這一點(diǎn)不適用于MyISAM。

書中的描述說(shuō)了幾個(gè)主要問(wèn)題,我這里暫且拋開MyISAM的問(wèn)題不談,這里我針對(duì)InnoDB作為考量條件。

  • 如果不設(shè)置NOT NULL的話,NULL是列的默認(rèn)值,如果不是本身需要的話,盡量就不要使用NULL
  • 使用NULL帶來(lái)更多的問(wèn)題,比如索引、索引統(tǒng)計(jì)、值計(jì)算更加復(fù)雜,如果使用索引,就要避免列設(shè)置成NULL
  • 如果是索引列,會(huì)帶來(lái)的存儲(chǔ)空間的問(wèn)題,需要額外的特殊處理,還會(huì)導(dǎo)致更多的存儲(chǔ)空間占用
  • 對(duì)于稀疏數(shù)據(jù)又更好的空間效率,稀疏數(shù)據(jù)指的是很多值為NULL,只有少數(shù)行的列有非NULL值的情況

默認(rèn)值

對(duì)于MySql而言,如果不主動(dòng)設(shè)置為NOT NULL的話,那么插入數(shù)據(jù)的時(shí)候默認(rèn)值就是NULL。

NULL和NOT NULL使用的空值代表的含義是不一樣,NULL可以認(rèn)為這一列的值是未知的,空值則可以認(rèn)為我們知道這個(gè)值,只不過(guò)他是空的而已。

舉個(gè)例子,一張表中的某一條name字段是NULL,我們可以認(rèn)為不知道名字是什么,反之如果是空字符串則可以認(rèn)為我們知道沒有名字,他就是一個(gè)空值。

而對(duì)于大多數(shù)程序的情況而言,沒有什么特殊需要非要字段要NULL的吧,NULL值反而會(huì)對(duì)程序造成比如空指針的問(wèn)題。

對(duì)于現(xiàn)狀大部分使用MyBatis的情況來(lái)說(shuō),我建議使用默認(rèn)生成的insertSelective方法或者純手動(dòng)寫插入方法,可以避免新增NOT NULL字段導(dǎo)致的默認(rèn)值不生效或者插入報(bào)錯(cuò)的問(wèn)題。

值計(jì)算

聚合函數(shù)不準(zhǔn)確

對(duì)于NULL值的列,使用聚合函數(shù)的時(shí)候會(huì)忽略NULL值。

現(xiàn)在我們有一張表,name字段默認(rèn)是NULL,此時(shí)對(duì)name進(jìn)行count得出的結(jié)果是1,這個(gè)是錯(cuò)誤的。

count(*)是對(duì)表中的行數(shù)進(jìn)行統(tǒng)計(jì),count(name)則是對(duì)表中非NULL的列進(jìn)行統(tǒng)計(jì)。

=失效

對(duì)于NULL值的列,是不能使用=表達(dá)式進(jìn)行判斷的,下面對(duì)name的查詢是不成立的,必須使用is NULL。

與其他值運(yùn)算

NULL和其他任何值進(jìn)行運(yùn)算都是NULL,包括表達(dá)式的值也是NULL。

user表第二條記錄age是NULL,所以+1之后還是NULL,name是NULL,進(jìn)行concat運(yùn)算之后結(jié)果還是NULL。

可以再看下下面的例子,任何和NULL進(jìn)行運(yùn)算的話得出的結(jié)果都會(huì)是NULL,想象下你設(shè)計(jì)的某個(gè)字段如果是NULL還不小心進(jìn)行各種運(yùn)算,最后得出的結(jié)果。。。

distinct、group by、order by

對(duì)于distinctgroup by來(lái)說(shuō),所有的NULL值都會(huì)被視為相等,對(duì)于order by來(lái)說(shuō)升序NULL會(huì)排在最前

其他問(wèn)題

表中只有一條有名字的記錄,此時(shí)查詢名字!=a預(yù)期的結(jié)果應(yīng)該是想查出來(lái)剩余的兩條記錄,會(huì)發(fā)現(xiàn)與預(yù)期結(jié)果不匹配。

索引問(wèn)題

為了驗(yàn)證NULL字段對(duì)索引的影響,分別對(duì)nameage添加索引。

關(guān)于網(wǎng)上很多說(shuō)如果NULL那么不能使用索引的說(shuō)法,這個(gè)描述其實(shí)并不準(zhǔn)確,根據(jù)引用官方文檔[3]里描述,使用is NULL和范圍查詢都是可以和正常一樣使用索引的,實(shí)際驗(yàn)證的結(jié)果好像也是這樣,看以下例子。

然后接著我們往數(shù)據(jù)庫(kù)中繼續(xù)插入一些數(shù)據(jù)進(jìn)行測(cè)試,當(dāng)NULL列值變多之后發(fā)現(xiàn)索引失效了。

我們知道,一個(gè)查詢SQL執(zhí)行大概是這樣的流程:

首先連接器負(fù)責(zé)連接到指定的數(shù)據(jù)庫(kù)上,接著看看查詢緩存中是否有這條語(yǔ)句,如果有就直接返回結(jié)果。

如果緩存沒有命中的話,就需要分析器來(lái)對(duì)SQL語(yǔ)句進(jìn)行語(yǔ)法和詞法分析,判斷SQL語(yǔ)句是否合法。

現(xiàn)在來(lái)到優(yōu)化器,就會(huì)選擇使用什么索引比較合理,SQL語(yǔ)句具體怎么執(zhí)行的方案就確定下來(lái)了。

最后執(zhí)行器負(fù)責(zé)執(zhí)行語(yǔ)句、有無(wú)權(quán)限進(jìn)行查詢,返回執(zhí)行結(jié)果。

從上面的簡(jiǎn)單測(cè)試結(jié)果其實(shí)可以看到,索引列存在NULL就會(huì)存在書中所說(shuō)的導(dǎo)致優(yōu)化器在做索引選擇的時(shí)候更復(fù)雜,更加難以優(yōu)化。

存儲(chǔ)空間

數(shù)據(jù)庫(kù)中的一行記錄在最終磁盤文件中也是以行的方式來(lái)存儲(chǔ)的,對(duì)于InnoDB來(lái)說(shuō),有4種行存儲(chǔ)格式:REDUNDANTCOMPACT、 DYNAMICCOMPRESSED。

InnoDB的默認(rèn)行存儲(chǔ)格式是COMPACT,存儲(chǔ)格式如下所示,虛線部分代表可能不一定會(huì)存在。

變長(zhǎng)字段長(zhǎng)度列表:有多個(gè)字段則以逆序存儲(chǔ),我們只有一個(gè)字段所有不考慮那么多,存儲(chǔ)格式是16進(jìn)制,如果沒有變長(zhǎng)字段就不需要這一部分了。

NULL值列表:用來(lái)存儲(chǔ)我們記錄中值為NULL的情況,如果存在多個(gè)NULL值那么也是逆序存儲(chǔ),并且必須是8bit的整數(shù)倍,如果不夠8bit,則高位補(bǔ)0。1代表是NULL,0代表不是NULL。如果都是NOT NULL那么這個(gè)就存在了。

ROW_ID:一行記錄的唯一標(biāo)志,沒有指定主鍵的時(shí)候自動(dòng)生成的ROW_ID作為主鍵。

TRX_ID:事務(wù)ID。

ROLL_PRT:回滾指針。

最后就是每列的值。

為了說(shuō)明清楚這個(gè)存儲(chǔ)格式的問(wèn)題,我弄張表來(lái)測(cè)試,這張表只有c1字段是NOT NULL,其他都是可以為NULL的。

可變字段長(zhǎng)度列表:c1c3字段值長(zhǎng)度分別為1和2,所以長(zhǎng)度轉(zhuǎn)換為16進(jìn)制是0x01 0x02,逆序之后就是0x02 0x01。

NULL值列表:因?yàn)榇嬖谠试S為NULL的列,所以c2,c3,c4分別為010,逆序之后還是一樣,同時(shí)高位補(bǔ)0滿8位,結(jié)果是00000010

其他字段我們暫時(shí)不管他,最后第一條記錄的結(jié)果就是,當(dāng)然這里我們就不考慮編碼之后的結(jié)果了。

這樣就是一個(gè)完整的數(shù)據(jù)行數(shù)據(jù)的格式,反之,如果我們把所有字段都設(shè)置為NOT NULL,并且插入一條數(shù)據(jù)a,bb,ccc,dddd的話,存儲(chǔ)格式應(yīng)該這樣:

雖然我們發(fā)現(xiàn)NULL本身并不會(huì)占用存儲(chǔ)空間,但是如果存在NULL的話就會(huì)多占用一個(gè)字節(jié)的標(biāo)志位的空間。

文章參考文檔:

https://dev.mysql.com/doc/refman/8.0/en/problems-with-null.html
https://dev.mysql.com/doc/refman/8.0/en/working-with-null.html
https://dev.mysql.com/doc/refman/5.6/en/is-null-optimization.html
https://dev.mysql.com/doc/refman/5.6/en/innodb-row-format.html
https://www.cnblogs.com/zhoujinyi/articles/2726462.html

到此這篇關(guān)于為什么mysql字段要使用NOT NULL的文章就介紹到這了,更多相關(guān)mysql字段使用NOT NULL內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何修改Mysql中g(shù)roup_concat的長(zhǎng)度限制

    如何修改Mysql中g(shù)roup_concat的長(zhǎng)度限制

    在mysql中,有個(gè)函數(shù)叫“group_concat”,平常使用可能發(fā)現(xiàn)不了問(wèn)題,在處理大數(shù)據(jù)的時(shí)候,會(huì)發(fā)現(xiàn)內(nèi)容被截取了。怎么解決這一問(wèn)題呢,下面腳本之家小編給大家?guī)?lái)了Mysql中g(shù)roup_concat的長(zhǎng)度限制問(wèn)題,感興趣的朋友一起看看吧
    2018-08-08
  • mysql主鍵和唯一鍵的使用與區(qū)別

    mysql主鍵和唯一鍵的使用與區(qū)別

    本文主要介紹了mysql主鍵和唯一鍵的使用與區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2026-02-02
  • MySQL 存儲(chǔ)引擎  MyISAM詳解(最新推薦)

    MySQL 存儲(chǔ)引擎  MyISAM詳解(最新推薦)

    使用 MyISAM 存儲(chǔ)引擎的表占用空間很小,但是由于使用表級(jí)鎖定,所以限制了讀/寫操作的性能,通常用于中小型的Web應(yīng)用和數(shù)據(jù)倉(cāng)庫(kù)配置中的只讀或主要是讀的場(chǎng)景,這篇文章主要介紹了MySQL 存儲(chǔ)引擎  MyISAM詳解,需要的朋友可以參考下
    2025-05-05
  • MySQL基礎(chǔ)教程之IN的用法詳解

    MySQL基礎(chǔ)教程之IN的用法詳解

    這篇文章主要介紹了MySQL基礎(chǔ)教程之IN的用法詳解的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • 關(guān)于k8s環(huán)境部署mysql主從的問(wèn)題

    關(guān)于k8s環(huán)境部署mysql主從的問(wèn)題

    這篇文章主要介紹了k8s環(huán)境部署mysql主從的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • MySQL數(shù)據(jù)庫(kù)服務(wù)器逐漸變慢分析與解決方法分享

    MySQL數(shù)據(jù)庫(kù)服務(wù)器逐漸變慢分析與解決方法分享

    本文針對(duì)MySQL數(shù)據(jù)庫(kù)服務(wù)器逐漸變慢的問(wèn)題, 進(jìn)行分析,并提出相應(yīng)的解決辦法
    2012-01-01
  • 阿里云服務(wù)器MySQL與nacos配置

    阿里云服務(wù)器MySQL與nacos配置

    本文主要介紹了阿里云服務(wù)器MySQL與nacos配置,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2026-03-03
  • MySQL數(shù)據(jù)庫(kù)性能優(yōu)化介紹

    MySQL數(shù)據(jù)庫(kù)性能優(yōu)化介紹

    大家好,本篇文章主要講的是MySQL數(shù)據(jù)庫(kù)性能優(yōu)化介紹,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • MySQL Workbench安裝及使用詳解

    MySQL Workbench安裝及使用詳解

    MySQL是一種關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),關(guān)系數(shù)據(jù)庫(kù)將數(shù)據(jù)保存在不同的表中,而不是將所有數(shù)據(jù)放在一個(gè)大倉(cāng)庫(kù)內(nèi),這樣就增加了速度并提高了靈活性,這篇文章主要介紹了MySQL Workbench安裝及使用,需要的朋友可以參考下
    2022-10-10
  • MySql安裝與使用圖文教程【推薦】

    MySql安裝與使用圖文教程【推薦】

    mysql是一種關(guān)聯(lián)數(shù)據(jù)庫(kù)管理系統(tǒng),在程序開發(fā)中應(yīng)用非常廣泛,下面通過(guò)本文給大家介紹mysql安裝與使用教程,感興趣的朋友一起學(xué)習(xí)吧
    2016-05-05

最新評(píng)論

永福县| 新河县| 谢通门县| 雷山县| 余姚市| 五原县| 阳朔县| 江达县| 大荔县| 武宣县| 景东| 天津市| 新干县| 林州市| 蓝田县| 张家川| 彰化县| 保亭| 三原县| 砚山县| 清河县| 元江| 绥芬河市| 正镶白旗| 长沙市| 婺源县| 武穴市| 集安市| 塔城市| 怀集县| 烟台市| 化德县| 兴宁市| 丰台区| 大埔县| 威宁| 潞西市| 凤城市| 华容县| 吴桥县| 竹山县|