mysql字段設(shè)置為null的問題解決
這個問題非常經(jīng)典,直接給你結(jié)論:
MySQL 中,字段允許為 NULL,索引依然可以正常使用,但在統(tǒng)計(jì)、查詢、存儲和性能上有幾個非常重要的“坑”需要注意。
我用最直白的方式給你講清楚。
1. 索引是否會失效?—— 不會
只要查詢條件寫對了,索引就能用。
-- 表 t,字段 name 允許 NULL,name 上有索引 SELECT * FROM t WHERE name = '張三'; -- ? 可以用索引 SELECT * FROM t WHERE name IS NULL; -- ? 也可以用索引(這個很多人誤以為不行)
關(guān)鍵點(diǎn):IS NULL 在索引中是有記錄的,MySQL 會把 NULL 值也存進(jìn)索引里(放在最前面或最后面,取決于引擎和排序方式)。
2. 最大的坑:COUNT、DISTINCT、分組統(tǒng)計(jì)會失真
這是最容易踩的坑,因?yàn)?NULL 在聚合函數(shù)里會被忽略。
| 操作 | 結(jié)果 | 原因 |
|---|---|---|
| COUNT(name) | 只統(tǒng)計(jì) 非 NULL 的行數(shù) | NULL 不算 |
| COUNT(*) | 統(tǒng)計(jì)所有行 | 不受 NULL 影響 |
| SUM(age) | 忽略 NULL 值 | NULL 不參與計(jì)算 |
| AVG(age) | 只算非 NULL 的平均值 | 分母不包含 NULL 的行 |
| DISTINCT name | 會把 NULL 當(dāng)作一個獨(dú)立值 | 多個 NULL 只算一個 |
示例:
-- 表里有 10 行,其中 3 行的 name 是 NULL SELECT COUNT(name) FROM t; -- 結(jié)果是 7,不是 10 ? SELECT COUNT(*) FROM t; -- 結(jié)果是 10 ?
教訓(xùn):如果你想要統(tǒng)計(jì)所有行,用 COUNT(*) 或 COUNT(主鍵),別用 COUNT(可為 NULL 的字段)。
3. 索引存儲和性能影響
① 索引大小會變大
- 每個 NULL 值在索引中也需要占用存儲空間(通常 1 個字節(jié)標(biāo)記是否為 NULL)。
- 如果字段允許 NULL,索引記錄會多一個 NULL 標(biāo)志位,導(dǎo)致索引稍微變大。
② 查詢效率略微下降
- 因?yàn)樗饕卸嗔艘粋€“是否為 NULL”的判斷邏輯。
- 但實(shí)際影響微乎其微,除非表非常巨大(幾億行),否則感覺不到。
③ 排序時 NULL 的位置
- InnoDB 中,NULL 在索引中默認(rèn)排在最前面(等價于最小值)。
- MyISAM 中,NULL 默認(rèn)排在最后面。
- 這會影響
ORDER BY的結(jié)果順序。
4. 組合索引中的 NULL 表現(xiàn)(很重要)
假設(shè)有組合索引 (a, b),兩個字段都允許 NULL:
-- 數(shù)據(jù): (1, 1) (1, NULL) (NULL, 2) (NULL, NULL)
索引能查到什么?
| 查詢 | 是否走索引 | 說明 |
|---|---|---|
| WHERE a = 1 | ? 走索引 | 正常 |
| WHERE a IS NULL | ? 走索引 | NULL 在索引中有記錄 |
| WHERE a = 1 AND b IS NULL | ? 走索引 | 組合索引完全匹配 |
| WHERE b = 2 | ? 不走索引 | 因?yàn)?b 是組合索引的第二列,不能跳過 a 單獨(dú)查 b |
核心:組合索引中,NULL 值也參與索引構(gòu)建,但最左前綴原則依然生效,不受 NULL 影響。
5. 一個容易被忽略的坑:NOT IN 和 NULL
SELECT * FROM t WHERE name NOT IN ('張三', '李四');
如果 name 允許 NULL,這個查詢會漏掉 name = NULL 的行!
原因:NULL 和任何值比較都是 UNKNOWN(既不是 TRUE 也不是 FALSE),所以 NOT IN 會排除掉所有含 NULL 的行。
正確做法:
SELECT * FROM t WHERE name NOT IN ('張三', '李四') OR name IS NULL;
6. 總結(jié)一張表(記住要點(diǎn))
| 問題 | 結(jié)論 |
|---|---|
| 允許 NULL 的字段能建索引嗎? | ? 可以 |
| IS NULL 能走索引嗎? | ? 可以 |
| 索引中 NULL 占空間嗎? | ? 占,略大一點(diǎn) |
| COUNT(字段) 會統(tǒng)計(jì) NULL 嗎? | ? 不會,只統(tǒng)計(jì)非 NULL |
| NOT IN 會包含 NULL 嗎? | ? 不會,需要額外加 OR IS NULL |
| 唯一索引允許多個 NULL 嗎? | ? 允許,多個 NULL 不沖突(因?yàn)?NULL != NULL) |
7. 最佳實(shí)踐建議
能設(shè)置 NOT NULL + 默認(rèn)值,就盡量別允許 NULL。
原因:
- 避免統(tǒng)計(jì)失真(COUNT、AVG 等)。
- 避免查詢條件中漏掉數(shù)據(jù)(NOT IN 等)。
- 索引存儲更小,性能略好。
- 應(yīng)用層不用處理 null 判空邏輯,代碼更干凈。
如果業(yè)務(wù)上確實(shí)需要表示“未知/無值”,那允許 NULL 也可以,但寫 SQL 時一定要留意上述坑。
到此這篇關(guān)于mysql字段設(shè)置為null的問題解決的文章就介紹到這了,更多相關(guān)mysql字段為null內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Centos7 安裝mysql 8.0.13(rpm)的教程詳解
這篇文章主要介紹了Centos7 安裝mysql 8.0.13(rpm)的教程詳解,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-11-11
MySQL的指定范圍隨機(jī)數(shù)函數(shù)rand()的使用技巧
這篇文章主要介紹了MySQL的指定范圍隨機(jī)數(shù)函數(shù)rand()的使用技巧,需要的朋友可以參考下2016-09-09
mysql存儲中使用while批量插入數(shù)據(jù)(批量提交和單個提交的區(qū)別)
這篇文章主要介紹了mysql存儲中使用while批量插入數(shù)據(jù)(批量提交和單個提交的性能差異),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08

