当前位置: 首页 > 科技观察

MySQL为Null会导致5个问题,都是致命的!

时间:2023-03-19 01:57:56 科技观察

本文转载自微信公众号“Java中文社区”,作者雷哥。转载本文请联系Java中文社区公众号。在正式开始之前,我们先看一下MySQL服务器的配置和版本号信息,如下图:“兵马未动粮草先”。看完相关配置,我们来创建一张测试表和一些测试数据。--如果有person表,先删除DROPTABLEIFEXISTSperson;--创建person表,username字段可以为空,并为其设置普通索引CREATETABLEperson(idINTPRIMARYKEYauto_increment,nameVARCHAR(20),mobileVARCHAR(13),index(name))ENGINE='innodb';--person表添加测试数据insertinperson(name,mobile)values('Java','13333333330'),('MySQL','13333333331'),('Redis','13333333332'),('Kafka','13333333333'),('Spring','13333333334'),('MyBatis','13333333335'),('RabbitMQ','13333333336'),('Golang','13333333337'),('C++','13333333338'),(NULL,'13333333339');select*fromperson;构造测试数据,如下图:有了数据后,我们看看有列中的NULL值有什么问题?1.count数据丢失当某列存在NULL值,再使用count查询该列,就会出现数据“丢失”的问题,如下SQL所示:selectcount(*),count(name)fromperson;query执行结果如下:从上面的结果可以看出,使用count(name)查询时,丢失了两条值为NULL的数据。解决方案如果某列存在NULL值,使用count(*)进行数据统计。扩展知识:不要用count(常量)阿里巴巴《Java开发手册》强制:不要用count(列名)或count(常量)代替count(),count()是SQL92定义的统计行数的标准语法,遵循by数据库与NULL和非NULL无关。解释:count(*)会统计值为NULL的行,count(columnname)不会统计值为NULL的行。2.Distinct数据丢失在使用count(distinctcol1,col2)查询时,如果其中一列为NULL,即使另一列有不同的值,查询结果也会丢失数据,如下SQL所示:selectcount(distinctname,mobile)fromperson;查询执行结果如下:数据库原始数据如下:从上面的结果可以看出,手机号这一列的10条数据都是不同的,但是查询的结果是8。3.selectdatalossifacolumn当有NULL值时,如果执行不等于查询(<>/!=),对于NULL值的结果会丢失。例如下面的数据:我需要查询除了name等于“Java”的所有数据,预期的结果是id从2到10的数据,但是当执行下面的查询时:select*frompersonwherename<>'Java'orderbyid;--或者select*frompersonwherename!='Java'orderbyid;查询结果都是这样的:可以看到这两条为NULL的数据凭空消失了,这个结果不符合我们正常的预期。解决方案解决上述问题,只需要在查询结果中加入NULL值的结果,执行SQL如下:select*frompersonwherename<>'Java'orisnull(name)orderbyid;最终执行结果如下:4.导致空指针异常如果某列存在NULL值,可能会导致sum(column)的返回结果为NULL,而不是0。如果sum查询的结果为NULL,则可能会导致程序执行时出现空指针异常(NPE)。让我们来演示这个问题。首先我们建表和一些测试数据:--如果有goods表,先删除DROPTABLEIFEXISTSgoods;--创建goods表CREATETABLEgoods(idINTPRIMARYKEYauto_increment,numint)ENGINE='innodb';--添加测试数据到goodstableinsertintogoods(num)values(3),(6),(6),(NULL);select*fromgoods;表中原始数据如下:接下来我们使用sum查询执行如下SQL:selectsum(num)fromgoodswhereid>4;查询执行结果如下:当查询结果为NULL而不是0时,可能会引发空指针异常。解决空指针异常,可以使用如下方法避免空指针异常:selectifnull(sum(num),0)fromgoodswhereid>4;查询执行结果如下:5.查询难度增加查询NULL值或非NULL值的难度增加。所谓增加查询难度是指在查询NULL值时,必须使用匹配NULL值的查询方法,如ISNULL或ISNOTNULL或IFNULL(cloumn)等表达式进行查询,而传统的=、!=,<>...等表达式不能使用,增加了查询的难度,特别是对于新手程序员。接下来,我们将演示这些问题。仍以person表为例,其原始数据如下:误用一:select*frompersonwherename<>null;执行结果为空,没有查询到任何数据,如下图:误用2:select*frompersonwherename!=null;执行结果也是空的,没有找到数据,如下图:正确用法1:select*frompersonwherenameisnotnull;执行结果如下:正确用法2:select*frompersonwhere!isnull(name);执行结果如下:推荐使用方法阿里巴巴《Java开发手册》推荐我们使用ISNULL(cloumn)来判断NULL值,因为在SQL语句中,如果在null之前换行,会影响可读性;而ISNULL(column)是一个整体,简洁易懂。从性能数据分析ISNULL(column)执行效率也更快。扩展知识:NULL不会影响索引细心的朋友可能发现了,我在创建person表的name字段的时候,为它创建了一个普通的索引,如下图:然后我们使用explain来分析查询计划看当name里面有NULL值的时候会不会影响索引的选择。explain的执行结果如下图所示:从上面的结果可以看出,即使名字中有NULL值,也不影响MySQL使用索引进行查询。总结这篇文章,我们讲了5种当列为NULL时可能导致的问题:丢失查询结果,导致空指针异常,增加查询难度。所以,最后还是建议大家尽量在建表的时候设置isnotnull约束。如果列没有值,您可以设置空值('')或0作为其默认值。