MaxCompute JOIN优化小结

本文涉及的产品
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
简介:

Join是MaxCompute中最基本的语法,但由于数据量和倾斜问题,非常容易出现性能问题。一般情况下,join产生的问题有两大类:

  • 数据倾斜问题:join会将key相同的数据分发到同一个instance上处理,如果某个key上的数据量特别多则会导致该instance处理时间比其他instance处理时间长,这就是我们常说的数据倾斜,这也是join计算性能问题的罪魁祸首;
  • 数据量问题:关联的两表基本没有热点问题,但两个表数据量都非常大同样会影响性能,比如记录数达几十亿条,如商品表、库存表等;

       虽然MaxCompute中提供了一些通用的优化算法,但从业务角度解决性能问题往往更精确,更有效。对于MaxCompute sql优化,在云栖社区上已经有比较多的经验积累,本文主要对join产生的性能问题以及解法做些总结。

不同数据类型key关联

例子

       浏览IPV日志以商品id关联商品表,假设日志表的商品id字段是string类型,商品表中的商品id是bigint类型,那么在关联中,关联key会全部转换成double类型进行比较,设想由于埋点问题日志表中的商品id存在很多非数值的脏数据,那么转换成double后值都变为NULL或者截取前面的数值,关联时就会产生数据倾斜问题,更严重的会造成数据错误。

解法

      关联时手工进行数据格式转换,在这种情况下一般将bigint类型key转换成string类型。

select a.* 
from ipv_log_table a 
left outer join item_table b 
on a.item_id = cast(b.item_id as string)

       思考下,假如反过来将string类型转换成bigint、假如IPV日志表中的商品id大部分为无效值(比如0)、又假如IPV日志表中没有无效值但是有热点key会有什么问题呢?下面的例子会解答这些问题。

小表join大表

         Join中存在小表,一般这个小表在100M以内,可以用mapjoin,避免分发引起的长尾。拿上面的例子来说,假如商品表数据量只有几万条记录(这里只是打个比方,现实业务中商品表一般都是非常庞大的),但是IPV日志表中的商品id 80%值为0的无效值,且记录数有几十亿,如果采用上述SQL写法,数据倾斜是显而易见的,但利用mapjoin可以有效解决这个问题:

select /*+ MAPJOIN(b) */a.* 
from ipv_log_table a 
left outer join item_table b 
on a.item_id = cast(b.item_id as string)

mapjoin原理       

       把小表广播传递到所有的Join Task Instance上面,然后直接和大表做Hash Join,简单的说就是将join操作提前到map端,而非reduce端。

mapjoin使用注意点

  • 小表在left outer join 时只能是右表, right outer join 时只能是左表, inner join 时无限制,full outer join不支持mapjoin;
  •  mapjoin最多只支持8张小表,否则会报语法错误;
  • mapjoin所有小表内存限制不能超过2GB,默认为512M;
  • mapjoin支持小表为子查询;
  • mapjoin支持不等值连接或者使用or连接多个条件;

大表join大表存在无效值

       在小表join大表时我们已经了解到通过mapjoin将小表全部加载到map端可以解决倾斜问题,但假如‘小表‘不够小,mapjoin失效的时候该怎么办呢?同样以本文第一个场景为例,IPV日志表中80%商品id都为无效值0(目前MaxCompute底层已经针对NULL值进行优化,已经不存在倾斜问题了),这时关联十几亿量级商品表那就是个灾难。

解法1-分而治之:

       我们可以事先知道无效值是不可能关联出结果的,而且完全不需要参与关联,所以可以将无效值与有效值数据分开处理:

select a.visitor_id
      ,b.seller_id
from (
      select 
      from ipv_log_table
      where item_id > 0
) a 
left outer join item_table b 
on a.item_id = b.item_id

union all

select a.visitor_id
      ,cast(null as bigint) seller_id
from ipv_log_table
where item_id = 0

解法2-随机值打散:

       我们也可以以随机值代替NULL值作为join的key,这样就从原来一个reduce来处理倾斜数据变成多reduce并行处理,因为无效值不参与关联,即使分发到不同reduce,也不会影响最终计算结果:

select a.visitor_id
      ,b.seller_id 
from ipv_log_table a 
left outer join item_table b 
on if(a.item_id > 0, cast(a.item_id as string), concat('rand',cast(rand() as string))) = cast(b.item_id as string)

解法3-转化为mapjoin:

      虽然商品表有十几亿条记录,不能直接通过mapjoin来处理,但在实际业务中,我们知道一天内用户访问的商品数是有限的,在业务中尤为明显,基于此我们可以通过一些处理转换成mapjoin:

select /*+ MAPJOIN(b) */
       a.visitor_id
      ,b.seller_id 
from ipv_log_table a 
left outer join (
   select /*+ MAPJOIN(log) */
         itm.seller_id 
        ,itm.item_id
   from (
         select item_id 
         from ipv_log_table 
         where item_id > 0
         group by item_id
   ) log join item_table itm
   on log.item_id = itm.item_id
) b 
on a.item_id = b.item_id

解法对比

       解法1和解法2是通用解决方案,对于解法1,日志表被读取两次,而解法2中只需读取一次,另外任务数解法2也是少于解法1的,所以总的来看解法2是优于解法1的。解法3是基于一定的假设,随着业务发展或者某些特殊情况下假设可能失效(比如一些爬虫日志,可造成访问商品数接近全量),这会导致mapjoin失效,所以在使用过程中要根据具体情况来评估。

一个古老的例子

       最后要讲一个古老的优化case,虽然历史比较久远,目前已没有相关问题,但优化思路值得借鉴。情况是这样的,历史上并存过两套商品维表,一份主键是字符串id,新的商品表也就是目前在使用的主键是数字id,字符串id和数字id做了映射,存在商品表中的两个字段中,所以在使用中需要分别过滤数字id、字符串id然后分别和商品表关联,最后union起来得到最终结果。

      思考下如果换成下面的优化思路是不是更优呢?

select ... 
from ipv_log_table a 
join (
      select auction_id as auction_id 
      from auctions
      union all
      select auction_string_id as auction_id 
      from auctions 
      where auction_string_id is not null
) b
on a.auction_id = b.auction_id

 

答案是肯定的,可以看到优化后商品表读取从2次降为1次,IPV日志表同样,另外MR作业数也从2个变为1个。

总结

       对于MaxCompute sql优化最有效的方式是从业务的角度切入,并能够将MaxCompute sql转化为mapreduce程序来解读。本文针对join中各种场景优化都做了一些梳理,现实情况很可能是上述多场景的组合,这时候就需要灵活运用相应的优化方法,举一反三。


作者:宋智

相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps 
相关文章
|
2月前
|
SQL 分布式计算 运维
如何对付一个耗时6h+的ODPS任务:慢节点优化实践
本文描述了大数据处理任务(特别是涉及大量JOIN操作的任务)中遇到的性能瓶颈问题及其优化过程。
|
6天前
|
存储 NoSQL 大数据
大数据 数据存储优化
【10月更文挑战第25天】
22 2
|
30天前
|
SQL 分布式计算 NoSQL
大数据-164 Apache Kylin Cube优化 案例1 定义衍生维度与对比 超详细
大数据-164 Apache Kylin Cube优化 案例1 定义衍生维度与对比 超详细
22 1
大数据-164 Apache Kylin Cube优化 案例1 定义衍生维度与对比 超详细
|
30天前
|
存储 大数据 分布式数据库
大数据-165 Apache Kylin Cube优化 案例 2 定义衍生维度及对比 & 聚合组 & RowKeys
大数据-165 Apache Kylin Cube优化 案例 2 定义衍生维度及对比 & 聚合组 & RowKeys
30 1
|
1月前
|
分布式计算 Java 大数据
大数据-92 Spark 集群 SparkRDD 原理 Standalone详解 ShuffleV1V2详解 RDD编程优化
大数据-92 Spark 集群 SparkRDD 原理 Standalone详解 ShuffleV1V2详解 RDD编程优化
35 0
大数据-92 Spark 集群 SparkRDD 原理 Standalone详解 ShuffleV1V2详解 RDD编程优化
|
30天前
|
SQL 存储 监控
大数据-161 Apache Kylin 构建Cube 按照日期、区域、产品、渠道 与 Cube 优化
大数据-161 Apache Kylin 构建Cube 按照日期、区域、产品、渠道 与 Cube 优化
43 0
|
1月前
|
SQL 分布式计算 大数据
大数据-91 Spark 集群 RDD 编程-高阶 RDD广播变量 RDD累加器 Spark程序优化
大数据-91 Spark 集群 RDD 编程-高阶 RDD广播变量 RDD累加器 Spark程序优化
30 0
|
3月前
|
存储 分布式计算 数据处理
MaxCompute 的成本效益分析与优化策略
【8月更文第31天】随着云计算技术的发展,越来越多的企业选择将数据处理和分析任务迁移到云端。阿里云的 MaxCompute 是一款专为海量数据设计的大规模数据仓库平台,它不仅提供了强大的数据处理能力,还简化了数据管理的工作流程。然而,在享受这些便利的同时,企业也需要考虑如何有效地控制成本,确保资源得到最优利用。本文将探讨如何评估 MaxCompute 的使用成本,并提出一些优化策略以降低费用,提高资源利用率。
193 0
|
3月前
|
大数据 RDMA
神龙大数据加速引擎MRACC问题之MRACC-Spark利用eRDMA近网络优化插件来提升性能如何解决
神龙大数据加速引擎MRACC问题之MRACC-Spark利用eRDMA近网络优化插件来提升性能如何解决
40 0
|
3月前
|
SQL 存储 分布式计算
神龙大数据加速引擎MRACC问题之RDMA技术帮助大数据分布式计算优化如何解决
神龙大数据加速引擎MRACC问题之RDMA技术帮助大数据分布式计算优化如何解决
55 0

相关产品

  • 云原生大数据计算服务 MaxCompute