首页 > 编程知识 正文

字段不能为null怎么办,数据库smallint

时间:2023-05-05 10:56:26 阅读:57428 作者:2559

我最近刚加入一家新公司,发现数据库的设计有点问题。 有这篇文章,因为数据库字段中通常没有NOT NULL,强迫症晚期患者无法忍受。

根据大多数当前开发现状,将所有字段设置为NOT NULL并指定默认值。

默认值通常设置为:

整形,我们通常使用0作为默认值。

字符串,默认空字符串

时间可以为1970-01-01 08:00:01或0000-00-0000336003360000,但连接参数必须为zerodatetimebehavior=converrer 请不要使用这个

但是,想想理由。 为什么要设置为NOT NULL?

高性能Mysql有以下语言:

尽量避免空值

许多表包含即使APP应用程序不需要存储空值也可以为空(NULL )的列。 这是因为列的缺省属性可以为null。 通常建议将列指定为NOT NULL,除非实际需要存储NULL值。

如果查询包含可空列,则MySql很难进行优化,因为索引、索引统计信息和值的比较很复杂。 可空列使用更多存储空间,MySql也需要特殊处理。 如果索引了可以为NULL的列,则每个索引记录都需要额外的字节。 在MyISAM中,固定大小的索引也可能是可变大小的索引,例如只有一个整数列的索引。

通常,将可空列更改为NOT NULL所带来的性能提高相对较小,因此不需要在现有架构中搜索和修复这种情况,除非确定会导致问题。 但是,在列上编制索引时,必须尽量避免设计为NULL的列。

当然也有例外,例如,InnoDB以单独的位存储空值,因此对稀疏数据有很好的空间效率。 但是,这不适用于MyISAM。

书中介绍了几个主要问题,这里暂且不谈MyISAM的问题,这里以InnoDB为考虑条件。

如果不设置NOT NULL,则NULL是列的缺省值,如果不需要它本身,则不要使用NULL

如果使用NULL,则会出现更多问题,如索引、索引统计信息和值的计算。 使用索引时,请勿将列设置为NULL

对于索引列,会出现存储容量问题,需要特殊处理,并且会消耗更多的存储容量

对于稀疏数据,请指向很多值为NULL,只有少数行的列有非NULL值

对于默认值MySql,如果不主动将其设置为NOT NULL,则插入数据时的默认值为NULL。

NULL和NOT NULL的含义不同。 NULL被认为此列的值未知,NULL被认为我们知道此值。 但是,他只是空的。

例如,如果某个表中的任何name字段为NULL,则可以认为是不知道名字是什么,相反,如果是空字符串,则可以认为是我们知道没有名字,他就是一个空值

对于大多数程序,没有必要特别指定字段必须为NULL。 空值反而会给程序带来空指针等问题。

目前,如果您使用的是大多数MyBatis,建议您使用缺省生成的insertSelective或纯手动写入插入方法。 这样可以避免由于添加NOT NULL字段而导致的默认值无效或出现插入错误的问题。

值计算聚合函数不准确

对于NULL值为的列,使用聚合函数将忽略NULL值。

现在有桌子。 name字段的默认值为NULL。 此时,如果计数name,则为1。 这是错误的。

count(*(* )计数表中的行数,count ) ) name计数表中的非空列。

=失效

对于空值的列,不能用=表达式确定。 以下对name的查询不成立,必须使用is NULL :

与其他值运算

NULL和其他所有值都为NULL,包含表达式的值也为NULL。

由于user表中的第二条记录age为NULL,因此1之后为NULL,name为NULL,执行concat运算后结果也为NULL。

看看下面的例子。 与NULL进行运算后得到的结果都为NULL。 如果您设计的任何字段为NULL,请不小心进行各种运算,想象最后得到的结果。

distinct、group by、order by

在distinct和group by中,所有NULL值都被视为相等,而在order by中,升序的NULL位于开头

其他问题

表中只有一条有名字的记录。 这个时候,我会查一下名字!=a预期的结果应该是想调查剩下的两个记录,可以看出和预期的结果不同

匹配。

索引问题

为了验证NULL字段对索引的影响,分别对name 和age添加索引。

关于网上很多说如果NULL那么不能使用索引的说法,这个描述其实并不准确,根据引用官方文档[3]里描述,使用is NULL和范围查询都是可以和正常一样使用索引的,实际验证的结果好像也是这样,看以下例子。

然后接着我们往数据库中继续插入一些数据进行测试,当NULL列值变多之后发现索引失效了。

我们知道,一个查询SQL执行大概是这样的流程:

首先连接器负责连接到指定的数据库上,接着看看查询缓存中是否有这条语句,如果有就直接返回结果。

如果缓存没有命中的话,就需要分析器来对SQL语句进行语法和词法分析,判断SQL语句是否合法。

现在来到优化器,就会选择使用什么索引比较合理,SQL语句具体怎么执行的方案就确定下来了。

最后执行器负责执行语句、有无权限进行查询,返回执行结果。

从上面的简单测试结果其实可以看到,索引列存在NULL就会存在书中所说的导致优化器在做索引选择的时候更复杂,更加难以优化。

存储空间

数据库中的一行记录在最终磁盘文件中也是以行的方式来存储的,对于InnoDB来说,有4种行存储格式:REDUNDANT、 COMPACT、 DYNAMIC 和 COMPRESSED。

InnoDB的默认行存储格式是COMPACT,存储格式如下所示,虚线部分代表可能不一定会存在。

变长字段长度列表:有多个字段则以逆序存储,我们只有一个字段所有不考虑那么多,存储格式是16进制,如果没有变长字段就不需要这一部分了。

NULL值列表:用来存储我们记录中值为NULL的情况,如果存在多个NULL值那么也是逆序存储,并且必须是8bit的整数倍,如果不够8bit,则高位补0。1代表是NULL,0代表不是NULL。如果都是NOT NULL那么这个就存在了。

ROW_ID:一行记录的唯一标志,没有指定主键的时候自动生成的ROW_ID作为主键。

TRX_ID:事务ID。

ROLL_PRT:回滚指针。

最后就是每列的值。

为了说明清楚这个存储格式的问题,我弄张表来测试,这张表只有c1字段是NOT NULL,其他都是可以为NULL的。

可变字段长度列表:c1和c3字段值长度分别为1和2,所以长度转换为16进制是0x01 0x02,逆序之后就是0x02 0x01。

NULL值列表:因为存在允许为NULL的列,所以c2,c3,c4分别为010,逆序之后还是一样,同时高位补0满8位,结果是00000010。

其他字段我们暂时不管他,最后第一条记录的结果就是,当然这里我们就不考虑编码之后的结果了。

这样就是一个完整的数据行数据的格式,反之,如果我们把所有字段都设置为NOT NULL,并且插入一条数据a,bb,ccc,dddd的话,存储格式应该这样:

虽然我们发现NULL本身并不会占用存储空间,但是如果存在NULL的话就会多占用一个字节的标志位的空间。

文章参考文档:

https://dev.mysql.com/doc/refman/8.0/en/problems-with-null.html

https://dev.mysql.com/doc/refman/8.0/en/working-with-null.html

https://dev.mysql.com/doc/refman/5.6/en/is-null-optimization.html

https://dev.mysql.com/doc/refman/5.6/en/innodb-row-format.html

https://www.cnblogs.com/zhoujinyi/articles/2726462.html

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。