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

