一、前言
我们在设计表的时候,经常会有老司机这么告诉我们。
字段尽可能用NOT NULL,而不是NULL,除非特殊情况。
这句话到底有没有错?
可以负责任的告诉你这句话没有错,也不是以讹传讹,这句话首次出现在 MySQL 官网。
MySQL 官网文档:
NULL columns require additional space in the rowto record whether their values are NULL. For MyISAM tables, each NULL columntakes one bit extra, rounded up to the nearest byte.
Mysql难以优化引用可空列查询,它会使索引、索引统计和值更加复杂。可空列需要更多的存储空间,还需要mysql内部进行特殊处理。可空列被索引后,每条记录都需要一个额外的字节,还能导致MYisam 中固定大小的索引变成可变大小的索引。
—— 出自《高性能mysql第二版》
二、不使用NOT NULL的原因
1、所有使用NULL值的情况,都可以通过一个有意义的值的表示,这样有利于代码的可读性和可维护性,并能从约束上增强业务数据的规范性。
2、NULL值到非NULL的更新无法做到原地更新,更容易发生索引分裂,从而影响性能。
注意:但把NULL列改为NOT NULL带来的性能提示很小,除非确定它带来了问题,否则不要把它当成优先的优化措施,最重要的是使用的列的类型的适当性。
3、NULL值在timestamp类型下容易出问题,特别是没有启用参数explicit_defaults_for_timestamp
4、NOT IN、!= 等负向条件查询在有 NULL 值的情况下返回永远为空结果,查询容易出错
5、Null 列需要更多的存储空间:需要一个额外字节作为判断是否为 NULL 的标志位
6、NULL
通过任一操作符与其它值比较都会得到NULL
,除了<=>
.
7、NULL 代表一个不确定的值,就算是两个 NULL,它俩也不一定相等.(像不像 C 中未初始化的局部变量)
8、任何有返回值的表达式中有NULL
参与时,都会得到另外一个NULL
值.
9、对含有 NULL 值的列进行统计计算 count()
,max()
,min()
,结果并不符合我们的期望值;使用count(*)
或者 count(null column)
结果不同,count(null column)
<=count(*)
.
10、干扰排序,分组,去重结果,虽然select NULL=NULL
的结果为false
,但是在我们使用distinct
,group by
,order by
时,NULL
又被认为是相同值
.
三、总结
MySQL不建议使用NULL作为列默认值的原因有几个。首先,NULL在SQL中表示“未知”,而不是“空”或“不存在”。当列被设置为NULL默认值时,它可能会导致查询和数据处理时的困惑和错误。
其次,使用NULL默认值可能会导致查询和处理数据时的复杂性增加。在查询中,需要额外处理NULL值的情况,这可能会使查询逻辑变得复杂且容易出错。此外,对NULL值进行数学运算或连接操作时,结果可能不符合预期,需要额外处理或排除NULL值。
另外,使用NULL默认值也会影响索引和性能。在数据库中,索引是提高查询性能的重要手段,但索引通常不会包含NULL值。如果列默认值为NULL,则该列中的大量数据可能为NULL,这会导致索引效率下降,进而影响查询性能。
综上所述,为了避免产生歧义、增加查询复杂性、影响索引和性能,MySQL不建议使用NULL作为列默认值。相反,建议使用适当的默认值或允许空字符串作为默认值,这样可以更直观、简洁地表达数据意图,并提高数据库查询和处理的效率和准确性。