null在where中需用is null而非=,比较操作结果为unknown;coalesce可兜底但影响索引;count(col)忽略null而count(*)统计所有行;not null对性能影响极小,关键在索引与查询逻辑。

NULL 值在 WHERE 条件中会意外失效
MySQL 里 NULL 不等于任何值,包括它自己。所以 WHERE status = NULL 永远不成立,必须写成 WHERE status IS NULL。业务代码里如果用 ORM 自动生成条件(比如 Django 的 filter(status=None)),多数能正确转成 IS NULL;但手写 SQL 或拼接字符串时极易踩坑。
- 所有涉及
NULL的比较操作(=、!=、、>等)结果都是UNKNOWN,被当作 false 过滤掉 -
COALESCE(status, 'unknown')或IFNULL(status, 'unknown')可临时兜底,但别滥用——它们会让索引失效 - 聚合函数如
COUNT(col)自动忽略NULL,而COUNT(*)统计所有行,这点常被误读
NOT NULL + DEFAULT 和允许 NULL 的性能差异很小
很多人以为加 NOT NULL 能省存储或提速,其实 InnoDB 对 NULL 列只多用 1 个 bit 记录空标志位,影响微乎其微。真正影响性能的是:是否建索引、索引列是否允许 NULL、以及查询时是否要频繁判断 IS NULL。
- 唯一索引(
UNIQUE)允许多行NULL(MySQL 特性),但如果你本意是“每个用户只能有一条未完成订单”,却把user_id设为允许NULL,就可能漏掉约束 -
NOT NULL列配合DEFAULT(如created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP)能减少应用层判空逻辑,也避免 ORM 插入时漏传字段报错 - JSON 类型列几乎总是设为
NULL允许,因为初始可能无数据;但像user_id这种强关联字段,NOT NULL是底线
DEFAULT 值选 '' 还是 NULL?看字段语义是否“缺失”
空字符串 '' 和 NULL 完全不是一回事:NULL 表示“未知/不适用/未采集”,'' 表示“明确知道是空”。比如用户没填昵称,是 NULL;但用户主动提交了空昵称,才该存 ''——不过后者极少有业务意义。
- 字符串类型慎用
DEFAULT '':容易和真实业务空值混淆(比如地址为空 vs 地址未填写) - 数值类型不要用
0代替NULL:订单金额为0是有效状态(免单),NULL才表示“还没算出金额” - 时间类型优先用
NOT NULL DEFAULT CURRENT_TIMESTAMP或NOT NULL DEFAULT '0000-00-00 00:00:00'(需关闭NO_ZERO_DATE模式),避免应用层反复校验
ALTER TABLE 修改 NULL 属性可能锁表
给已有大表加 NOT NULL 约束(尤其带 DEFAULT)在 MySQL 5.7 及以前会触发全表拷贝,线上执行风险极高。8.0+ 支持部分 DDL 原地修改,但仍有例外。
-
ALTER TABLE t MODIFY COLUMN name VARCHAR(50) NOT NULL DEFAULT ''—— 如果原列有NULL数据,会报错,必须先UPDATE清洗 - 想删掉
NOT NULL很安全,但反过来加约束前务必确认存量数据无NULL - 用
pt-online-schema-change或gh-ost工具在线变更更稳妥,但要注意工具对DEFAULT值的处理逻辑
NULL 的理解可能完全相反。与其靠文档约定,不如在建表语句里写清楚注释,比如 status TINYINT COMMENT '订单状态:1=待支付,2=已完成;NULL=创建失败未初始化'。











