前言
null在数据中是一个很特殊的存在,我们实际经历多起生产事故,而且直接就带来直接的经济损失,这个值在实际使用的时候很容易被用错,今天我们来盘点一下null带来的坑吧。
对常见几种空的理解
比较结果错误
首先还是准备数据
create table tmp_null_test as select id,col from values(1,null) ,(2,'v2') ,(3,'v3') ,(null,'v4') t(id,col); select * from tmp_null_test; id col 1 \N 2 v2 3 v3 \N v4
最常见的就是我们期望获取null的值,比如我们很自然的想到列=null的情况
select * from tmp_null_test where col=null;
这个结果很诡异,实际上是查询不到结果的,我们直接看一下如果col=null是怎样的结果:
select id,col,col=null as pk from tmp_null_test; id col pk 1 \N \N 2 v2 \N 3 v3 \N \N v4 \N
特别的神奇,pk结果清一色\N,这样告诉我们获取null这样子是会错误的,null和任何结果比较其实都是无意义的。
怎么办呢?一般有下面些办法:
1、使用 is null
select id,col,col is null as pk from tmp_null_test; id col pk 1 \N true 2 v2 false 3 v3 false \N v4 false
2、使用 COALESCE/nvl函数把null转化掉,再进行过滤
select id,col,COALESCE(col,'')='' from tmp_null_test; id col _c2 1 \N true 2 v2 false 3 v3 false \N v4 false
select id,col,nvl(col,'')='' from tmp_null_test; id col _c2 1 \N true 2 v2 false 3 v3 false \N v4 false
大量null导致倾斜
null带来的倾斜主要有两种,一种是明确告诉你有null,再join我们倒是比较好发现,还一种是在隐式转换的时候带来了null这种很难发现,这个就是null阳谋和阴谋,不管那种情况,在数据体量比较大的时候,其实都会带来极差的性能。
阳谋
一般在数据内部有null的时候,我们直接用来做join,数据量大的时候就是很慢,甚至运行不出来,这种时候也是null的问题,这种情况需要看业务场景是否需要转化掉
阴谋
有一种情况存在,如下面图中的id,左边是字符串类型,右边其实是double类型,这种时候在做join的时候取值a,b的时候并不能转化成double,这个时候也会产生null
这种时候产生的null还不是直接产生的,是在做隐式转换的时候发生的,这个时候会导致异常,这种情况很难发现,我记得我们排查了大半年。后面发现问题之后,是需要提前把右边id转换成String类型,再做join。配上sql来说明:
第一次的样子:
select t1.id,t1.name,t2.name from table1 t1 join table2 t2 on t1.id=t2.id
实际转换路径如下:
要注意的是这个操作是隐式的,可以在日志上面看到,但是一般人不感知,这种时候会造成null
解决办法:
select t1.id,t1.name,t2.name from table1 join (selec cast(id as string) as id,name from table2) t2 on t1.id=t2.id
这种方式是主动把原来是double类型的id主动转换成字符串,带来的是下面的效果:
null占空间极小,改变了分发策略
在orc格式的存储时代,大量null的数据存在在一个很小的空间中,通过测试发现一个2M的文件,可以存储2亿行的数据,这种时候2m引擎会认为你是小文件,从而直接进行广播,结构就是导致Driver端的OOM,这种时候出现了很多起事故。
怎么解决呢?发现了直接禁止掉了广播了
后记
null需要小心使用,否则~