91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

數(shù)據(jù)庫字段要使用NOT NULL究竟是為何?

數(shù)據(jù)分析與開發(fā) ? 來源:博客園 ? 作者:艾小仙 ? 2021-04-19 15:24 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

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

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

通常,對于默認(rèn)值一般這樣設(shè)置:

整形,我們一般使用0作為默認(rèn)值。

字符串,默認(rèn)空字符串

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

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

來自高性能Mysql中有這樣一段話:

盡量避免NULL

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

如果查詢中包含可為NULL的列,對MySql來說更難優(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帶來的性能提升比較小,所以(調(diào)優(yōu)時(shí))沒有必要首先在現(xiàn)有schema中查找并修改掉這種情況,除非確定這會(huì)導(dǎo)致問題。但是,如果計(jì)劃在列上建索引,就應(yīng)該盡量避免設(shè)計(jì)成可為NULL的列。

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

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

如果不設(shè)置NOT NULL的話,NULL是列的默認(rèn)值,如果不是本身需要的話,盡量就不要使用NULL

使用NULL帶來更多的問題,比如索引、索引統(tǒng)計(jì)、值計(jì)算更加復(fù)雜,如果使用索引,就要避免列設(shè)置成NULL

如果是索引列,會(huì)帶來的存儲(chǔ)空間的問題,需要額外的特殊處理,還會(huì)導(dǎo)致更多的存儲(chǔ)空間占用

對于稀疏數(shù)據(jù)有更好的空間效率,稀疏數(shù)據(jù)指的是很多值為NULL,只有少數(shù)行的列有非NULL值的情況

默認(rèn)值

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

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

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

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

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

值計(jì)算

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

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

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

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

5e7ffcca-9f5a-11eb-8b86-12bb97331649.jpg

=失效

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

5e908a04-9f5a-11eb-8b86-12bb97331649.jpg

與其他值運(yùn)算

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

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

5e98c872-9f5a-11eb-8b86-12bb97331649.jpg

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

5ea43040-9f5a-11eb-8b86-12bb97331649.jpg

distinct、group by、order by

對于distinct和group by來說,所有的NULL值都會(huì)被視為相等,對于order by來說升序NULL會(huì)排在最前

5eca059a-9f5a-11eb-8b86-12bb97331649.jpg

其他問題

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

5ed4b576-9f5a-11eb-8b86-12bb97331649.jpg

索引問題

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

5eea93f0-9f5a-11eb-8b86-12bb97331649.jpg

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

5ef74ffa-9f5a-11eb-8b86-12bb97331649.jpg

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

5f027aec-9f5a-11eb-8b86-12bb97331649.jpg

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

5f0caefe-9f5a-11eb-8b86-12bb97331649.jpg

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

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

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

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

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

存儲(chǔ)空間

數(shù)據(jù)庫中的一行記錄在最終磁盤文件中也是以行的方式來存儲(chǔ)的,對于InnoDB來說,有4種行存儲(chǔ)格式:REDUNDANT、COMPACT、DYNAMIC和COMPRESSED。

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

5f14e5e2-9f5a-11eb-8b86-12bb97331649.jpg

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

NULL值列表:用來存儲(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:回滾指針。

最后就是每列的值。

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

5f25503a-9f5a-11eb-8b86-12bb97331649.jpg

可變字段長度列表:c1和c3字段值長度分別為1和2,所以長度轉(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é)果了。

5f464196-9f5a-11eb-8b86-12bb97331649.jpg

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

5f55fdf2-9f5a-11eb-8b86-12bb97331649.jpg

雖然我們發(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

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • SQL
    SQL
    +關(guān)注

    關(guān)注

    1

    文章

    790

    瀏覽量

    46725
  • 數(shù)據(jù)庫
    +關(guān)注

    關(guān)注

    7

    文章

    4020

    瀏覽量

    68375
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4417

    瀏覽量

    67565
  • null
    +關(guān)注

    關(guān)注

    0

    文章

    19

    瀏覽量

    4311

原文標(biāo)題:為什么數(shù)據(jù)庫字段要使用NOT NULL?

文章出處:【微信號(hào):DBDevs,微信公眾號(hào):數(shù)據(jù)分析與開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    艾體寶干貨 | 多模型數(shù)據(jù)庫解決的到底是什么問題?

    了其設(shè)計(jì)的核心初衷。要精準(zhǔn)理解多模型數(shù)據(jù)庫,需先跳出“功能誤區(qū)”,回歸問題本質(zhì):企業(yè)系統(tǒng)的數(shù)據(jù)庫復(fù)雜度,究竟源于何處? 系統(tǒng)變復(fù)雜,往往不只是因?yàn)?b class='flag-5'>數(shù)據(jù)量,還有
    的頭像 發(fā)表于 02-03 16:08 ?328次閱讀

    國產(chǎn)數(shù)據(jù)庫的AI戰(zhàn)事

    國產(chǎn)數(shù)據(jù)庫硝煙再起,Vastbase V100構(gòu)筑企業(yè)智能基座
    的頭像 發(fā)表于 10-24 20:45 ?4071次閱讀
    國產(chǎn)<b class='flag-5'>數(shù)據(jù)庫</b>的AI戰(zhàn)事

    華納云為游戲數(shù)據(jù)庫選擇高性能NVMe SSD存儲(chǔ)

    的關(guān)鍵因素,尤其是在香港服務(wù)器租用環(huán)境中。 為何游戲數(shù)據(jù)庫需要高性能存儲(chǔ) 游戲數(shù)據(jù)庫因其動(dòng)態(tài)化和實(shí)時(shí)性需求,與傳統(tǒng)數(shù)據(jù)庫存在顯著差異。這些需求包括: 高并發(fā),可處理數(shù)千名玩家的同時(shí)交互
    的頭像 發(fā)表于 09-30 16:03 ?1091次閱讀

    數(shù)據(jù)庫性能優(yōu)化指南

    作為一名在大廠摸爬滾打多年的運(yùn)維老兵,我見過太多因?yàn)?b class='flag-5'>數(shù)據(jù)庫性能問題導(dǎo)致的生產(chǎn)事故。今天分享一套完整的數(shù)據(jù)庫優(yōu)化方法論,從SQL層面到硬件配置,幫你徹底解決性能瓶頸!
    的頭像 發(fā)表于 08-18 11:21 ?761次閱讀

    數(shù)據(jù)庫數(shù)據(jù)恢復(fù)—服務(wù)器異常斷電導(dǎo)致Oracle數(shù)據(jù)庫故障的數(shù)據(jù)恢復(fù)案例

    Oracle數(shù)據(jù)庫故障: 某公司一臺(tái)服務(wù)器上部署Oracle數(shù)據(jù)庫。服務(wù)器意外斷電導(dǎo)致數(shù)據(jù)庫報(bào)錯(cuò),報(bào)錯(cuò)內(nèi)容為“system01.dbf需要更多的恢復(fù)來保持一致性”。該Oracle數(shù)據(jù)庫
    的頭像 發(fā)表于 07-24 11:12 ?661次閱讀
    <b class='flag-5'>數(shù)據(jù)庫</b><b class='flag-5'>數(shù)據(jù)</b>恢復(fù)—服務(wù)器異常斷電導(dǎo)致Oracle<b class='flag-5'>數(shù)據(jù)庫</b>故障的<b class='flag-5'>數(shù)據(jù)</b>恢復(fù)案例

    三款主流國產(chǎn)數(shù)據(jù)庫的技術(shù)特點(diǎn)

    隨著數(shù)字經(jīng)濟(jì)的快速發(fā)展和數(shù)據(jù)安全要求的提升,國產(chǎn)數(shù)據(jù)庫正迎來前所未有的發(fā)展機(jī)遇。在信創(chuàng)浪潮推動(dòng)下,達(dá)夢數(shù)據(jù)庫、TiDB、華為高斯數(shù)據(jù)庫等國產(chǎn)數(shù)據(jù)庫
    的頭像 發(fā)表于 07-14 11:08 ?1182次閱讀

    數(shù)據(jù)庫數(shù)據(jù)恢復(fù)—MongoDB數(shù)據(jù)庫文件丟失的數(shù)據(jù)恢復(fù)案例

    MongoDB數(shù)據(jù)庫數(shù)據(jù)恢復(fù)環(huán)境: 一臺(tái)操作系統(tǒng)為Windows Server的虛擬機(jī)上部署MongoDB數(shù)據(jù)庫。 MongoDB數(shù)據(jù)庫故障: 工作人員在MongoDB服務(wù)仍
    的頭像 發(fā)表于 07-01 11:13 ?652次閱讀
    <b class='flag-5'>數(shù)據(jù)庫</b><b class='flag-5'>數(shù)據(jù)</b>恢復(fù)—MongoDB<b class='flag-5'>數(shù)據(jù)庫</b>文件丟失的<b class='flag-5'>數(shù)據(jù)</b>恢復(fù)案例

    數(shù)據(jù)庫數(shù)據(jù)恢復(fù)—SQL Server數(shù)據(jù)庫被加密如何恢復(fù)數(shù)據(jù)?

    SQL Server數(shù)據(jù)庫故障: SQL Server數(shù)據(jù)庫被加密,無法使用。 數(shù)據(jù)庫MDF、LDF、log日志文件名字被篡改。
    的頭像 發(fā)表于 06-25 13:54 ?693次閱讀
    <b class='flag-5'>數(shù)據(jù)庫</b><b class='flag-5'>數(shù)據(jù)</b>恢復(fù)—SQL Server<b class='flag-5'>數(shù)據(jù)庫</b>被加密如何恢復(fù)<b class='flag-5'>數(shù)據(jù)</b>?

    大促數(shù)據(jù)庫壓力激增,如何一眼定位 SQL 執(zhí)行來源?

    你是否曾經(jīng)遇到過這樣的情況:在大促活動(dòng)期間,用戶訪問量驟增,數(shù)據(jù)庫的壓力陡然加大,導(dǎo)致響應(yīng)變慢甚至服務(wù)中斷?更讓人頭疼的是,當(dāng)你試圖快速定位問題所在時(shí),卻發(fā)現(xiàn)難以確定究竟是哪個(gè)業(yè)務(wù)邏輯中的 SQL
    的頭像 發(fā)表于 06-10 11:32 ?573次閱讀
    大促<b class='flag-5'>數(shù)據(jù)庫</b>壓力激增,如何一眼定位 SQL 執(zhí)行來源?

    oracle數(shù)據(jù)恢復(fù)—oracle數(shù)據(jù)庫誤執(zhí)行錯(cuò)誤truncate命令如何恢復(fù)數(shù)據(jù)

    oracle數(shù)據(jù)庫誤執(zhí)行truncate命令導(dǎo)致數(shù)據(jù)丟失是一種常見情況。通常情況下,oracle數(shù)據(jù)庫誤操作刪除數(shù)據(jù)只需要通過備份恢復(fù)數(shù)據(jù)
    的頭像 發(fā)表于 06-05 16:01 ?1165次閱讀
    oracle<b class='flag-5'>數(shù)據(jù)</b>恢復(fù)—oracle<b class='flag-5'>數(shù)據(jù)庫</b>誤執(zhí)行錯(cuò)誤truncate命令如何恢復(fù)<b class='flag-5'>數(shù)據(jù)</b>?

    SQLSERVER數(shù)據(jù)庫是什么

    SQL Server 是由微軟公司開發(fā)的一款 關(guān)系型數(shù)據(jù)庫管理系統(tǒng)(RDBMS) ,用于存儲(chǔ)、管理和檢索結(jié)構(gòu)化數(shù)據(jù)。它是企業(yè)級(jí)應(yīng)用中廣泛使用的數(shù)據(jù)庫解決方案之一,尤其適用于Windows平臺(tái),但也
    的頭像 發(fā)表于 05-26 09:19 ?1185次閱讀

    MySQL數(shù)據(jù)庫是什么

    開發(fā)、企業(yè)應(yīng)用和大數(shù)據(jù)場景。以下是其核心特性和應(yīng)用場景的詳細(xì)說明: 核心特性 關(guān)系型數(shù)據(jù)庫模型 數(shù)據(jù)以 表(Table) 形式組織,表由行(記錄)和列(字段)構(gòu)成。 通過 主鍵、外鍵
    的頭像 發(fā)表于 05-23 09:18 ?1238次閱讀

    FOC電機(jī)控制究竟該如何學(xué)?

    學(xué)習(xí)FOC電機(jī)控制究竟是學(xué)哪些內(nèi)容? 電機(jī)知識(shí) 軟件知識(shí) 純分享貼,有需要可以直接下載附件獲取完整資料! (如果內(nèi)容有幫助可以關(guān)注、點(diǎn)贊、評(píng)論支持一下哦~)
    發(fā)表于 05-09 14:09

    SEGGER emFile支持大型數(shù)據(jù)庫

    SEGGER宣布emFile對大型數(shù)據(jù)庫的支持,集成了SQLite,方便與SEGGER的BigFAT和微軟的exFAT一起使用。
    的頭像 發(fā)表于 04-23 15:51 ?803次閱讀

    數(shù)據(jù)庫數(shù)據(jù)恢復(fù)——MongoDB數(shù)據(jù)庫文件拷貝后服務(wù)無法啟動(dòng)的數(shù)據(jù)恢復(fù)

    MongoDB數(shù)據(jù)庫數(shù)據(jù)恢復(fù)環(huán)境: 一臺(tái)Windows Server操作系統(tǒng)虛擬機(jī)上部署MongoDB數(shù)據(jù)庫。 MongoDB數(shù)據(jù)庫故障: 管理員在未關(guān)閉MongoDB服務(wù)的
    的頭像 發(fā)表于 04-09 11:34 ?878次閱讀
    <b class='flag-5'>數(shù)據(jù)庫</b><b class='flag-5'>數(shù)據(jù)</b>恢復(fù)——MongoDB<b class='flag-5'>數(shù)據(jù)庫</b>文件拷貝后服務(wù)無法啟動(dòng)的<b class='flag-5'>數(shù)據(jù)</b>恢復(fù)