impala 执行计划详解

Impala是一个MPPMassivelyParallelProcessing计算引擎,简单来说就是将计算压力分到多个节点,得到结果后汇总,然后再返回给客户端。如果你留意过Impala的执行计划,会观察到exchange节点,该节点的作用就是分散计算压力的过程,impala的架构相关,可点击关于MySQL,PostgreSQL,Impala,Spark的执行计划

下面我们通过sql语句 + 截图的方式熟悉下impala的执行计划

查看impala的执行情况有3种途径, 1️⃣ execution planSQL没有实际运行之前就可以获取;2️⃣ profile SQL实际运行之后搜集的执行信息;3️⃣ summary也是SQL实际执行之后搜集的信息相比于profile更加详细

本文将重点探讨第一种execution plan的执行

1️⃣ 常见SQL及其执行计划

测试表表结构及数据状况如下

drop table if exists  test.user;
create table if not exists test.user as
select 1 as user_id , 'z1' as user_name union all
select 2 as user_id , 'z2' as user_name union all
select 3 as user_id , 'z3' as user_name
;
drop table if exists test.goods;
create table if not exists test.goods as
select '001' as goods_id , '手机' as  goods_name union all
select '002' as goods_id , '洗衣机' as  goods_name union all
select '003' as goods_id , '冰箱' as  goods_name ;
;

drop table if exists test.order_tb;
create table if not exists test.order_tb as
select 1 as order_no , 1 as user_id , '001' as goods_id union all
select 2 as order_no , 1 as user_id , '002' as goods_id union all
select 3 as order_no , 2 as user_id , '002' as goods_id
;

1.1 select 查询

impala 执行计划详解_第1张图片

简单的select * 操作,exechange中不需要partitioned,且没有搜集表的统计信息,基数cardinality信息不可用unaviable

1.2 group by

impala 执行计划详解_第2张图片

左边的逻辑是执行表扫描之后,进行一次预聚合然后按照user_id的哈希值分发,相同user_id去往同一个节点之后,merge结果;右侧和左侧的区别在于执行了compuate status之后,统计到数据都在一个节点,所以只需要单节点内的聚合

1.3 order by

impala 执行计划详解_第3张图片

左图:首先节点内排序,排序完成后所有节点归并外排即归并排序1。右图中搜集了目标表的统计信息,只需要在单节点内执行排序操作

1.4 windows_function

impala 执行计划详解_第4张图片

左图中首先按照partition by分区字段exechange往不同的节点,然后是排序user_id正序null值排在队首,然后是执行窗口操作,可以观察到实际使用的是rows between unbounded preceding and current row队首到当前行,最后exechange之后返回结果,相比于order by 的排序的区别在于没有最终归并排序的步骤。右图的区别在于搜集到目标表的统计信息后,所有操作在单节点内完成

1.5 join

impala 执行计划详解_第5张图片

左图中:扫描t2表后广播t2表,关联方式为hash join ,关联完成后扫描t3表,广播t3后,和t1关联,关联方式为hash join,最后exechange返回结果。右图中搜集到了各个表的统计信息后,t1和t2关联,之后t3 right join t1表。二者使用的方式都是Hash Join,关于Hash Join可以参考这篇文章单机与分布式下的 Join 是怎么玩的?

在没有收集表信统计信息的情况下,Impala不会知道谁是大表谁是小表,也就无法完成类似Hive优化器那样,总是用小表驱动大表的功能

2️⃣-大表关联

上面描述的表数据量很小,是小表之间的关联,下面描述的是大表之间的关联及其执行计划

  • dwd.live_order_basic_di ,dwd.live_order_goods_di 亿级记录的的大表
  • dim.live_zhubo_user_info_df 小表(千条记录)

2.1 大表关联大表&大表关联小表

impala 执行计划详解_第6张图片

️左图是大表关联小表,可以认为是广播哈希关联

  • 扫描t1表,
  • 扫描t2,exechange的方式是广播
  • t1表和t2表hash join
  • 节点内聚合
  • 按照分组键 anchor_id 执行exechange
  • merge多个节点的结果
  • exechange 给协调器QueryCoordinator

️右图是大表关联大表,可以认为是混洗哈希关联

  • 扫描t1表,并且按照关联键exechange
  • 扫描t2表,并且按照关联键exechange (经过步骤1和步骤2之后,相同的关联键都去往同一个节点)
  • 执行hash join
  • 按照分组键anchor_id聚合(节点内聚合)
  • 按照分组键anchor_id exechange(相同的分组键去往相同的节点)
  • merge多个节点的结果
  • exechange 给协调器QueryCoordinator

下图是两种关联方式的区别:

impala 执行计划详解_第7张图片

2.2-group by + distinct单字段

impala 执行计划详解_第8张图片

上图左图和右图展示了,如果group by A字段,distinct B字段的实际效果就是先group by A, B字段,然后在按照其中一个字段group by,然后执行聚合函数

2.3-group by + distinct多个字段

impala 执行计划详解_第9张图片

如上图所示,如果对多个字段执行distinct,将会有多个分组calss_x同时进行,这对impalad的压力是非常大的,生产环境中多字段distict非常容易把impalad玩坏

3-其他问题

️ 关于为什么有时候执行compute stats tb_name时候,整体脚本更慢?

情况1:执行explain的时候即便没有表的统计信息也会生成一个执行计划,按照该执行计划执行得到耗时为 t i m e _ A time\_A time_A

情况2:假设执行compute stats tb_name的耗时为 t i m e _ B time\_B time_B,但是在执行explain之后得到了和情况1一样的执行计划,此时整体消耗的时间为: t i m e _ A + t i m e _ B time\_A + time\_B time_A+time_B

‍♂ 所以一个建议是在涉及大表的查询/关联时,不建议优先执行 compute stats tb_name

Impala在没有收集统计信息的前提下,执行关联有如下逻辑

1️⃣ t1 left join t2exchange (哈希或者广播) t2表

2️⃣ t1 right join t2 , exchange (哈希或者广播) t1表

️ 关于行列剪裁的辨析

projection投影 pushdown predicate谓词 pushdown runtime filter
列过滤 行过滤(更底层的过滤方式) 行过滤(运行加载到内存过滤)

关于predicate pushdowruntime filter的区别

This optimization is called filter pushdown or predicate pushdown and aims at pushing down the filtering to the “bare metal”, i.e. a data source engine. That is to increase the performance of queries since the filtering is performed at the very low level rather than dealing with the entire dataset after it has been loaded to Spark’s memory and perhaps causing memory issues.

由于谓词下推predicatePushdown是一种更底层的过滤方式,因此比较于运行时过滤runtimeFilter具备更高的效率

本文首发于公众号stackoverflow,欢迎关注

Reference


  1. 几乎无一例外的,只要涉及到大规模数据的排序,都需要使用归并排序,因为归并排序的优势在于可以突破内存的限制,而且是一个 O ( n ∗ l o g n ) O(n*log^n) O(nlogn)的时间复杂度的排序方式 ↩︎

你可能感兴趣的:(大数据,数据库,sql)