【转载】MaxCompute full outer join改写left anti join实践

本文涉及的产品
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
简介: ods层数据同步时经常会遇到增全量合并的模型,即T-1天增量表 + T-2全量表 = T-1全量表。可以通过full outer join脚本来完成合并,但是数据量很大时非常消耗资源。本文将为您介绍在做增量数据的增加、更新时如何通过full outer join改写left anti join来实现的最佳实践。

背景

ods层数据同步时经常会遇到增全量合并的模型,即T-1天增量表 + T-2全量表 = T-1全量表。可以通过full outer join脚本来完成合并,但是数据量很大时非常消耗资源。

insert overwrite table tb_test partition(ds='${bizdate}')
select case when a.id is not null then a.id esle b.id end as id   
      ,if(a.name is not null, a.name, b.name) as name
      ,coalesce(a.age, b.age) as age 
      --这3种写法一样,都是优先取delta表的字段

from
(
   select * from tb_test_delta where ds='${bizdate}'
) a
full outer join
(
   select * from tb_test where ds='${bizdate-1}'
) b
on a.id =b.id;

这种写法可实现新增和更新操作:

  • 新增是指增量表中新出现的数据,而全量表中没有;
  • 更新是指增量表和全量表中都有的数据,但优先取增量表的数据,覆盖历史表的数据。
    如下图所示,R2_1是增量表当天去重后增量数据,M3是全量表前一天的数据,而J4_2_3则是full outer join的执行图。

image.png

将J4_2_3展开会发现里面将增量和全量进行了merge join,当数据量很大(1288亿条)时会产生很大的shuffle开销。此时优化方案就是将full outer join改成 union all,从而避免join shuffle

优化模型

结论:full outer join改成hash cluster + left join +union all可以有效地降低计算成本,且有两种应用场景。先将模型进行抽象,假设有a和b两个表,a是增量表,b是全量表:

with 
 a as ( select * from values  (1,'111')
                             ,(2,'two')
                             ,(7,'777') as (id,name) ) --增量

,b as ( select * from values  (1,'')
                             ,(2,'222')
                             ,(3,'333')
                             ,(4,'444') as (id,name) )  --全量

场景1:只合并新增数据到全量表

left anti join相当于not in,增量not in全量,过滤后只剩下完全新增的id,对全量中已有的id不修改:

--查询完全新增的id
select * from a left anti join b on a.id=b.id ;
--结果如下
+------------+------+
| id         | name |
+------------+------+
| 7          | 777  |
+------------+------+
--完全新增的合并全量表
select * from  a --增量表
left anti join b on a.id=b.id  
union all 
select * from b  --全量表
--结果如下
+------------+------+
| id         | name |
+------------+------+
| 1          |      |
| 2          | 222  |
| 3          | 333  |
| 4          | 444  |
| 7          | 777  |
+------------+------+

场景2:合并新增数据到全量表,且更新历史数据

全量not in增量,过滤后只剩下历史的id,然后union all增量,既新增也修改

--查询历史全量数据
select * from b left anti join a on a.id=b.id;
--结果如下
+------------+------+
| id         | name |
+------------+------+
| 3          | 333  |
| 4          | 444  |
+------------+------+
--合并新增数据到全量表,且更新历史数据
select * from  b --全量表
left anti join a on a.id=b.id
union all 
select * from a ; --增量表
--结果如下
+------------+------+
| id         | name |
+------------+------+
| 1          | 111  |
| 2          | two  |
| 7          | 777  |
| 3          | 333  |
| 4          | 444  |
+------------+------+

优化实践

步骤1:表属性修改

表、作业属性修改,对原来的表、作业进行属性优化,可以提升优化效果。

set odps.sql.reducer.instances=3072;  --可选。默认最大1111个reducer,1111哈希桶。
alter table table_name clustered by(contact_id) sorted by(contact_id) into 3072 buckets;--必选

步骤2:按照上述模型的场景1 或者 场景2进行代码改造。

这里先给出代码改造后的资源消耗对比:

原来的full outer jion left anti join初始化 原来的full outer jion left anti join第二天以后
时间消耗 8h30min38s 1h4min48s 7h32min30s 32min30s
cpu消耗 29666.02 Core * Min 65705.30 Core * Min 31126.86 Core * Min 30589.29 Core * Min
mem消耗 109640.80 GB * Min 133922.25 GB * Min 114764.80 GB * Min 65509.28 GB * Min

可以发现hash cluster分桶操作在初始化有额外的开销,主要是按主键进行散列和排序,但是这是值得的,可一劳永逸,后续的读取速度非常快。以前每天跑需要8小时,现在除了分桶初始化需要1小时,以后每天实际只需要30分钟。

初始化执行图

图1:
image.png

  • M2是读全量表。
  • M4是读取增量表,在场景2的模型中增量表被读取了两次,其中:

    • R5_4是对主键去重(row_number)后用于后面的union all,里面包含了所有的增量数据;
    • R1_4是对主键去重(row_number)后用于left anti join,里面只包含了主键。
  • J3_1_2是left anti join,将它展开后看到这里还是有mergJoin,但是这只是初始化的操作,后面每天就不会有了。展开后如图2。
  • R6_3_5是将增量和全量进行union all,展开后如图3。
  • R7_6则是将索引信息写入元数据,如图3的MetaCollector1会在R7_6中sink。
    因此:图1中除了R5_4和R1_4是去重必须的,有shuffle。还有J3_1_2和R6_3_5这两个地方有shuffle。

图2:
image.png

图3:
image.png

第二天以后的执行图

图1:
image.png

同上,图1中的R3_2和R1_2是对增量去重必要对操作,有shuffle,这里忽略。

初始化执行图的J3_1_2和R6_3_5已经被合并到了M4_1_3,将其展开后如图2。即left anti join 和 union all这两步操作在一个阶段完成了,且这个阶段是Map 任务(M4_1_3),而不是Join任务或Reduce任务。而且全量表不在单独占用一个Map任务,也被合并到了M4_1_3,因此整个过程下来没有shuffle操作,速度提升非常明显。也就是说只需要一个M4_1_3就能完成所有到操作,直接sink到表。

R5_4则是将索引信息写入元数据,如图2的MetaCollector1会在R5_4中sink。

图2:
image.png

原创:阿里菜鸟-数据 鹤方

相关实践学习
基于MaxCompute的热门话题分析
Apsara Clouder大数据专项技能认证配套课程:基于MaxCompute的热门话题分析
目录
相关文章
|
2月前
|
数据采集 SQL 搜索推荐
大数据之路:阿里巴巴大数据实践——OneData数据中台体系
OneData是阿里巴巴内部实现数据整合与管理的方法体系与工具,旨在解决指标混乱、数据孤岛等问题。通过规范定义、模型设计与工具平台三层架构,实现数据标准化与高效开发,提升数据质量与应用效率。
大数据之路:阿里巴巴大数据实践——OneData数据中台体系
|
3月前
|
分布式计算 监控 大数据
大数据之路:阿里巴巴大数据实践——离线数据开发
该平台提供一站式大数据开发与治理服务,涵盖数据存储计算、任务调度、质量监控及安全管控。基于MaxCompute实现海量数据处理,结合D2与DataWorks进行任务开发与运维,通过SQLSCAN与DQC保障代码质量与数据准确性。任务调度系统支持定时、周期、手动运行等多种模式,确保高效稳定的数据生产流程。
大数据之路:阿里巴巴大数据实践——离线数据开发
|
3月前
|
数据采集 存储 大数据
大数据之路:阿里巴巴大数据实践——日志采集与数据同步
本资料全面介绍大数据处理技术架构,涵盖数据采集、同步、计算与服务全流程。内容包括Web/App端日志采集方案、数据同步工具DataX与TimeTunnel、离线与实时数仓架构、OneData方法论及元数据管理等核心内容,适用于构建企业级数据平台体系。
|
3月前
|
数据采集 分布式计算 DataWorks
ODPS在某公共数据项目上的实践
本项目基于公共数据定义及ODPS与DataWorks技术,构建一体化智能化数据平台,涵盖数据目录、归集、治理、共享与开放六大目标。通过十大子系统实现全流程管理,强化数据安全与流通,提升业务效率与决策能力,助力数字化改革。
98 4
|
3月前
|
分布式计算 DataWorks 数据处理
在数据浪潮中前行:记录一次我与ODPS的实践、思考与展望
本文详细介绍了在 AI 时代背景下,如何利用阿里云 ODPS 平台(尤其是 MaxCompute)进行分布式多模态数据处理的实践过程。内容涵盖技术架构解析、完整操作流程、实际部署步骤以及未来发展方向,同时结合 CSDN 博文深入探讨了多模态数据处理的技术挑战与创新路径,为企业提供高效、低成本的大规模数据处理方案。
212 3
|
2月前
|
存储 SQL 分布式计算
大数据之路:阿里巴巴大数据实践——元数据与计算管理
本内容系统讲解了大数据体系中的元数据管理与计算优化。元数据部分涵盖技术、业务与管理元数据的分类及平台工具,并介绍血缘捕获、智能推荐与冷热分级等技术创新。元数据应用于数据标签、门户管理与建模分析。计算管理方面,深入探讨资源调度失衡、数据倾斜、小文件及长尾任务等问题,提出HBO与CBO优化策略及任务治理方案,全面提升资源利用率与任务执行效率。
|
3月前
|
机器学习/深度学习 存储 分布式计算
ODPS驱动电商仓储革命:动态需求预测系统的落地实践
本方案基于ODPS构建“预测-仿真-决策”闭环系统,解决传统仓储中滞销积压与爆款缺货问题。通过动态特征工程、时空融合模型与库存仿真引擎,实现库存周转天数下降42%,缺货率下降65%,年损减少5000万以上,显著提升运营效率与GMV。
246 1
|
4月前
|
资源调度 安全 Java
Java 大数据在智能教育在线实验室设备管理与实验资源优化配置中的应用实践
本文探讨Java大数据技术在智能教育在线实验室设备管理与资源优化中的应用。通过统一接入异构设备、构建四层实时处理管道及安全防护双体系,显著提升设备利用率与实验效率。某“双一流”高校实践显示,设备利用率从41%升至89%,等待时间缩短78%。该方案降低管理成本,为教育数字化转型提供技术支持。
102 1
|
3月前
|
SQL 人工智能 分布式计算
在数据浪潮中前行:我与ODPS的实践、思考与展望
在数据驱动决策的时代,企业如何高效处理海量数据成为数字化转型关键。本文结合作者实践,深入解析阿里云自研大数据平台 ODPS 的技术优势与应用场景,涵盖 MaxCompute、DataWorks、Hologres 等核心产品,分享从数据治理到实时分析的落地经验,并展望其在 AI 与向量数据时代的发展前景。
201 70

热门文章

最新文章

相关产品

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