使用 MySQL 數(shù)據(jù)庫時(shí),對于一個(gè)可以為空的字段,如果沒有值,應(yīng)該保存 NULL 還是給一個(gè)默認(rèn)值呢?多數(shù)時(shí)候我們不太注意,有時(shí)候不賦值,直接保存 NULL,有時(shí)候賦值一個(gè)業(yè)務(wù)指定的默認(rèn)值。今天來聊一聊這個(gè)話題。
1.行數(shù)據(jù)存儲
MySQL 保存一行數(shù)據(jù)時(shí),不僅僅會(huì)保存數(shù)據(jù)本身,還會(huì)保存數(shù)據(jù)相關(guān)的額外信息。InnoDB 存儲引擎支持四種行格式,MySQL 5.7 版本之后,默認(rèn)使用 Dynamic 行格式。看一下官網(wǎng)給出的 4 種格式說明:
![]()
DYNAMIC 和 COMPRESSED 這兩種格式都是 COMPACT 的改進(jìn)版,基本結(jié)構(gòu)跟 COMPACT 類似,我們看一下 COMPACT 這種格式。如下圖:
我們創(chuàng)建一張表:
CREATE TABLE`t_user` (`id`bigint(20) NOTNULL AUTO_INCREMENT,`name`varchar(16) DEFAULTNULL,`email`varchar(32) DEFAULTNULL,`address`varchar(255) DEFAULTNULL,PRIMARY KEY (`id`)) ENGINE=InnoDBDEFAULTCHARSET=latin1;插入 2 行數(shù)據(jù),
![]()
數(shù)據(jù)行保存格式如下圖:
![]()
變長字段寬度列表保存變長字段非空值長度。從上圖可以看到,變長字段寬度列表存放的列寬度順序和數(shù)據(jù)表中的列順序相反,也就是說變長字段寬度列表逆序存放列寬度。
![]()
如果表中所有列都是NOT NULL并且具有固定長度,則沒有變長字段寬度列表這個(gè)部分
同樣,NULL 值列表也是逆序保存,當(dāng)該值是 NULL 時(shí),用二進(jìn)制 1 表記,否則就保存二進(jìn)制 0。
![]()
如果表中所有列都是NOT NULL,就沒有 NULL值列表這個(gè)部分。
記錄頭信息用 5 個(gè)字節(jié)保存,主要記錄數(shù)據(jù)的一些信息,比如:
delete-flag:記錄是否刪除,我們知道,在 MySQL 中刪除一條數(shù)據(jù),并不會(huì)馬上從磁盤上刪除,而是打上刪除標(biāo)記,在空余時(shí)間再進(jìn)行異步清理。
record_type:記錄類型,比如普通記錄、非葉子節(jié)點(diǎn)記錄。
next_record:指向下一條記錄的地址指針。
n_owned:記錄該組數(shù)據(jù)的條數(shù)。
隱藏列
DB_TRX_ID:修改(插入、更新或刪除)這一條數(shù)據(jù)的事務(wù) id;
DB_ROLL_PTR:回滾指針,指向修改前的歷史版本,用于回滾操作;
DB_ROW_ID:當(dāng)表中不定義主鍵時(shí)用作主鍵來自動(dòng)生成聚簇索引。
根據(jù)上面的分析和實(shí)際使用,如果我們把一個(gè)字段直接定義成 NOT NULL,有下面好處:
節(jié)省存儲空間:NULL 值雖然不會(huì)占用數(shù)據(jù)存儲空間,但是需要額外 1~2 個(gè)字節(jié)保存 NULL 值列表。
減少應(yīng)用程序 NullPointerException 的可能性;
減少統(tǒng)計(jì)問題:比如 count(字段)不會(huì)統(tǒng)計(jì) NULL 值。
對索引有好處,索引是不會(huì)保存 NULL 值的,定義成 NULL 會(huì)使索引效率下降。
比較操作:字段定義成 NULL,只能使用 is null 和 is not null 進(jìn)行判斷,不能使用比較操作比如 =、!=、>、<(都會(huì)返回 null) 。
范圍操作:字段定義成 NULL,使用 in、not in 語句時(shí)會(huì)返回空結(jié)果。
當(dāng)然,設(shè)置為 NULL,并不是沒有好處,比如:
語義清晰?:NULL 表示“無值”或“未知”,這在邏輯上更清晰準(zhǔn)確;
靈活性?:NULL 值更容易篩選,比如在 WHERE 子句中使用 is null 進(jìn)行篩選;
兼容性?:類似 JOIN 操作,NULL 跟任何值比較都會(huì)返回 NULL,這有助于保持?jǐn)?shù)據(jù)的一致性和完整性。
在實(shí)際項(xiàng)目開發(fā)中,我們經(jīng)常會(huì)在值是 NULL 的情況下給一個(gè)默認(rèn)值,比如”-“、”“、”N/A“等,這一定程度上避免了空指針,但是往往帶來一些額外的問題,比如上下游系統(tǒng)因?yàn)槟J(rèn)值的不一致導(dǎo)致業(yè)務(wù)處理受影響。
在表設(shè)計(jì)時(shí),我們其實(shí)沒有必要過多地考慮定義成 NULL 或默認(rèn)值在存儲空間上的影響,更多的應(yīng)該考慮系統(tǒng)整體設(shè)計(jì)規(guī)范、保證各子系統(tǒng)在設(shè)計(jì)上的一致性,這樣才能讓處理邏輯更加健壯。
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.