面試官:MySQL 空值字段應該保存 NULL 還是默認值?
大家好,我是君哥。
使用 MySQL 數據庫時,對于一個可以為空的字段,如果沒有值,應該保存 NULL 還是給一個默認值呢?多數時候我們不太注意,有時候不賦值,直接保存 NULL,有時候賦值一個業務指定的默認值。今天來聊一聊這個話題。
1.行數據存儲
MySQL 保存一行數據時,不僅僅會保存數據本身,還會保存數據相關的額外信息。InnoDB 存儲引擎支持四種行格式,MySQL 5.7 版本之后,默認使用 Dynamic 行格式。看一下官網給出的 4 種格式說明:
行格式 | 緊湊的存儲特性 | 增強的可變長度列存儲 | 大索引鍵前綴支持 | 壓縮支持 | 表空間類型支持 | 文件格式 |
REDUNDANT | No | No | No | No | system, file-per-table, general | Antelope or Barracuda |
COMPACT | Yes | No | No | No | system, file-per-table, general | Antelope or Barracuda |
DYNAMIC | Yes | Yes | Yes | No | system, file-per-table, general | Barracuda |
COMPRESSED | Yes | Yes | Yes | Yes | file-per-table, general | Barracuda |
DYNAMIC 和 COMPRESSED 這兩種格式都是 COMPACT 的改進版,基本結構跟 COMPACT 類似,我們看一下 COMPACT 這種格式。如下圖:
圖片
我們創建一張表:
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 行數據,
圖片
數據行保存格式如下圖:
圖片
變長字段寬度列表保存變長字段非空值長度。從上圖可以看到,變長字段寬度列表存放的列寬度順序和數據表中的列順序相反,也就是說變長字段寬度列表逆序存放列寬度。
圖片
如果表中所有列都是 NOT NULL 并且具有固定長度,則沒有變長字段寬度列表這個部分。
同樣,NULL 值列表也是逆序保存,當該值是 NULL 時,用二進制 1 表記,否則就保存二進制 0。
圖片
如果表中所有列都是 NOT NULL,就沒有 NULL 值列表這個部分。
記錄頭信息用 5 個字節保存,主要記錄數據的一些信息,比如:
- delete-flag:記錄是否刪除,我們知道,在 MySQL 中刪除一條數據,并不會馬上從磁盤上刪除,而是打上刪除標記,在空余時間再進行異步清理。
- record_type:記錄類型,比如普通記錄、非葉子節點記錄。
- next_record:指向下一條記錄的地址指針。
- n_owned:記錄該組數據的條數。
隱藏列:
- DB_TRX_ID:修改(插入、更新或刪除)這一條數據的事務 id;
- DB_ROLL_PTR:回滾指針,指向修改前的歷史版本,用于回滾操作;
- DB_ROW_ID:當表中不定義主鍵時用作主鍵來自動生成聚簇索引。
2.NULL 處理
根據上面的分析和實際使用,如果我們把一個字段直接定義成 NOT NULL,有下面好處:
- 節省存儲空間:NULL 值雖然不會占用數據存儲空間,但是需要額外 1~2 個字節保存 NULL 值列表。
- 減少應用程序 NullPointerException 的可能性;
- 減少統計問題:比如 count(字段)不會統計 NULL 值。
- 對索引有好處,索引是不會保存 NULL 值的,定義成 NULL 會使索引效率下降。
- 比較操作:字段定義成 NULL,只能使用 is null 和 is not null 進行判斷,不能使用比較操作比如 =、!=、>、<(都會返回 null) 。
- 范圍操作:字段定義成 NULL,使用 in、not in 語句時會返回空結果。
當然,設置為 NULL,并不是沒有好處,比如:
- 語義清晰:NULL 表示“無值”或“未知”,這在邏輯上更清晰準確;
- 靈活性:NULL 值更容易篩選,比如在 WHERE 子句中使用 is null 進行篩選;
- 兼容性:類似 JOIN 操作,NULL 跟任何值比較都會返回 NULL,這有助于保持數據的一致性和完整性。
在實際項目開發中,我們經常會在值是 NULL 的情況下給一個默認值,比如”-“、”“、”N/A“等,這一定程度上避免了空指針,但是往往帶來一些額外的問題,比如上下游系統因為默認值的不一致導致業務處理受影響。
在表設計時,我們其實沒有必要過多地考慮定義成 NULL 或默認值在存儲空間上的影響,更多的應該考慮系統整體設計規范、保證各子系統在設計上的一致性,這樣才能讓處理邏輯更加健壯。

























