0X00 前提
技术选型:阿里云Maxcompute 2.0
场景:普通的日常模型开发,原有的模型宽表基础上通过left outer join获取新的维度信息。操作:A LEFT OUTER JOIN B ON A.ID=B.CID;
0x01 过程
分析:
- A表80w数据量,B表200w。一开始怀疑是因为小表左关联大表导致数据量翻倍,但是通过另外一个50w行记录的C表左关联B表实验,得到结果接近50w,即排除因为小表关联大表的原因导致数据翻倍;
- 接下来是排除数据质量问题,对关联条件的字段做了空值、空白值、非常见符号剔除等操作。通过查询A表:
insert overwrite table A_b select distinct id from A
,获得A表中所有唯一的id,然后A_b和B表full join 得80w数据量结果集。数据质量没有问题; - 按理A和B表是一对一关系,左关联后数据量应该接近A表的80w行,但实际结果是200w左右接近B表,拿了其中一个值为6956667891XXX002的id的记录为例子进行查询,按理结果应该只有一条,记录里面来源A表的字段id和来源B表的字段cid应该都是6956667891XXX002。然而事实大跌眼镜,出现两条记录:
id | cid |
---|---|
6956667891XXX002 | 6956667891XXX002 |
6956667891XXX002 | 6956667891XXX005 |
- 第二行记录不应该出现的记录只是最后一位不一样,怀疑是关联时把id(多为数字)截断来比较了
- 最后开始怀疑是因为表结构在建表时某些参数没设置好导致的问题(其实已经开始怀疑人生了…)。在对比A、B、A_b三个表结构的时候,忽然发现,关联条件id在A表中是bigint类型,而B、C、A_b表中均为string类型,于是在关联时做了强制类型转换:A LEFT OUTER JOIN B ON cast(A.ID AS STRING)=B.CID; 最后结果:
id | cid |
---|---|
6956667891XXX002 | 6956667891XXX002 |
0X02 解决
阿里云平台上的Maxcompute在做表之间关联时(不管左右关联、全关联等等),都需要确保表之间用来做关联的条件字段,一定是相同类型,否则会出现上述关联时两条不一样但相似的关联值被当作正确值带出来。如果关联条件字段类型不一致,可以通过cast()函数来进行类型强制转换。
0X03 反思
以前在使用hive的时候是不需要关心字段类型的,因为在做关联条件两端匹配时,会自动转换成字符串然后按照字段顺序进行比较、匹配。估计阿里云Maxcompute底层是做强类型定义的,需要精确控制存储大小,而与hive的读模式不一样。
这个问题是我接手客户公司原有的阿里云数仓做重构时发现,看来以后可以开两个新坑:
- 数据仓库重构之路
- 各大NoSQL机制、方案比较
(无脑立Flag多多见谅,保命手动狗头doge)