淺談為什么數(shù)據(jù)庫字段建議設(shè)置為NOT NULL
一、性能
如果查詢中包含可為null的列,對MYSQL來說更難優(yōu)化,因?yàn)榭蔀閚ull的列使得索引、索引統(tǒng)計(jì)和值比較都更復(fù)雜??蔀閚ull的列會使用更多的存儲空間,在MYSQL里也需要特殊處理。當(dāng)可為null的列被索引時(shí),每個(gè)索引記錄需要一個(gè)額外的字節(jié),在MyISAM里甚至還可能導(dǎo)致固定大小的索引(例如只有一個(gè)整數(shù)列的索引)變成可變大小的索引。
通常把可為null的列改為not null帶來的性能提升比較小,所以(調(diào)優(yōu)時(shí))沒有必要首先在現(xiàn)有schema中查找并修改掉這種情況,除非確定這會導(dǎo)致問題。但是,如果計(jì)劃在列上建索引,就應(yīng)該盡量避免設(shè)計(jì)成可為null的列。
當(dāng)然也有例外,例如值得一提的是,InnoDB使用單獨(dú)的位(bit)存儲null值,所以對于稀疏數(shù)據(jù)有很好的空間效率。但這一點(diǎn)不適用于MyISAM。
注意:稀疏數(shù)據(jù)指的是很多值為null,只有少數(shù)行的列有非null值的情況。
二、開發(fā)的友好性
可以減少對空值的額外處理邏輯,開發(fā)人員可以更加簡潔和清晰的編寫代碼。
三、聚合函數(shù)不準(zhǔn)確
對于null值的列,使用聚合函數(shù)的時(shí)候會忽略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ì)。
四、null與其它值計(jì)算
null和其他任何值進(jìn)行運(yùn)算都是null,包括表達(dá)式的值也是null。比如null+1等于null,concat()函數(shù)拼接也還是null。
五、distinct、group by、order by的問題
對于distinct和group by來說,所有的null值都會被視為相等,對于order by來說升序null會排在最前。

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

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

然后接著我們往數(shù)據(jù)庫中繼續(xù)插入一些數(shù)據(jù)進(jìn)行測試,當(dāng)null列值變多之后發(fā)現(xiàn)索引失效了。
我們知道,一個(gè)查詢SQL執(zhí)行大概是這樣的流程:

首先連接器負(fù)責(zé)連接到指定的數(shù)據(jù)庫上,接著看看查詢緩存中是否有這條語句,如果有就直接返回結(jié)果。
如果緩存沒有命中的話,就需要分析器來對SQL語句進(jìn)行語法和詞法分析,判斷SQL語句是否合法。
現(xiàn)在來到優(yōu)化器,就會選擇使用什么索引比較合理,SQL語句具體怎么執(zhí)行的方案就確定下來了。
最后執(zhí)行器負(fù)責(zé)執(zhí)行語句、有無權(quán)限進(jìn)行查詢,返回執(zhí)行結(jié)果。
從上面的簡單測試結(jié)果其實(shí)可以看到,索引列存在null就會導(dǎo)致優(yōu)化器在做索引選擇的時(shí)候更復(fù)雜,更加難以優(yōu)化。
七、其它問題
表中只有一條有名字的記錄,此時(shí)查詢名字!=a預(yù)期的結(jié)果應(yīng)該是想查出來剩余的兩條記錄,會發(fā)現(xiàn)與預(yù)期結(jié)果不匹配。

到此這篇關(guān)于為什么數(shù)據(jù)庫字段建議設(shè)置為NOT NULL的文章就介紹到這了,更多相關(guān)數(shù)據(jù)庫字段NOT NULL內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
新推出的金融版eXtremeDB 6.0功能改進(jìn)預(yù)覽
這篇文章主要介紹了新推出的金融版eXtremeDB 6.0功能改進(jìn)預(yù)覽,如運(yùn)用SQL, Python實(shí)現(xiàn)的基于矢量的統(tǒng)計(jì)功能、分布式的查詢處理、市場數(shù)據(jù)壓縮等內(nèi)容,需要的朋友可以參考下2014-10-10
dbeaver批量導(dǎo)出數(shù)據(jù)到另一個(gè)數(shù)據(jù)庫的詳細(xì)圖文教程
DBeaver是一款數(shù)據(jù)庫管理軟件,小巧易用,最主要其官方版就可以滿足平常得任務(wù)需求,這篇文章主要給大家介紹了關(guān)于dbeaver批量導(dǎo)出數(shù)據(jù)到另一個(gè)數(shù)據(jù)庫的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03
sql優(yōu)化實(shí)戰(zhàn) 把full join改為left join +union all(從5分鐘降為10秒)
因?yàn)樘厥庠颍瑹o法訪問客戶的服務(wù)器,沒辦法查看sql的執(zhí)行計(jì)劃、沒辦法知道表中的索引情況,所以,嘗試從語句的改寫上來優(yōu)化2020-09-09
openGauss數(shù)據(jù)庫在CentOS上的安裝實(shí)踐記錄
這篇文章主要介紹了openGauss數(shù)據(jù)庫在CentOS上的安裝實(shí)踐,本文是基于華為云ECS+CentOS 7的openGauss數(shù)據(jù)庫安裝實(shí)踐,需要的朋友可以參考下2022-07-07
如何用DeepSeek獲取數(shù)據(jù)庫中的表信息(表名和字段名稱)
這篇文章主要介紹了如何利用DeepSeek模型結(jié)合數(shù)據(jù)庫查詢,自動生成表結(jié)構(gòu)信息,通過自然語言描述,讓DeepSeek自動生成對應(yīng)的SQL查詢,從而實(shí)現(xiàn)對數(shù)據(jù)庫結(jié)構(gòu)的智能化探索,需要的朋友可以參考下2025-02-02
Hive數(shù)據(jù)去重的兩種方式?(distinct和group?by)
數(shù)據(jù)庫中表存在重復(fù)數(shù)據(jù),需要清理重復(fù)數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于Hive數(shù)據(jù)去重的兩種方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
Access轉(zhuǎn)換成SQL Server需要注意事項(xiàng)整理
很多朋友想用SQL2000數(shù)據(jù)庫的編程方法,但是卻又苦于自己是學(xué)ACCESS的,對SQL只是一點(diǎn)點(diǎn)的了解而已,這里我給大家提供以下參考---將ACCESS轉(zhuǎn)化成SQL2000的方法和注意事項(xiàng)2008-04-04
數(shù)據(jù)庫設(shè)計(jì)規(guī)范化的五個(gè)要求 推薦收藏
通常情況下,可以從兩個(gè)方面來判斷數(shù)據(jù)庫是否設(shè)計(jì)的比較規(guī)范。一是看看是否擁有大量的窄表,二是寬表的數(shù)量是否足夠的少。2011-04-04

