❶ Hive数仓-数据倾斜优化
首先倾斜一般发生在rece阶段
-- 解决方案
Hive默认启动Map join 优化
如果是查询的语句列如(group, join)可以直接在yarn kill掉
如果是 insert ,,, select 就要权衡 等他跑完
结束后 对sql语句发生数据倾斜的地方烂尘进行定位、给出解决方案、测试、变更
可以要对进行join 或者group by 的字段采样
列如 订单表1000w条数据 商品表100w条数据
a.pid = b.pid
select pid ,count(*) from tb_order group by pid;
查看一下订单表中 商品key的个数
列如商品1 900w条 那么这个数据一定会发生数据倾斜
textfile 文本文件 hdfs 默认存储
SequenceFile 二进制文件 使用二进制字节码存储 存储方式为行存储,其具有使用方便、可分割、
可压缩的特点
RCfile 、
ORCfile 列式存储
行式存储 方便插入 列式存储 方便查询
:相比TEXTFILE和SEQUENCEFILE,RCFILE由于列式存搏岁储方式,数据加载时性基历睁能消耗较大,但是具有较好
的压缩比和查询响应。
数据仓库的特点是一次写入、多次读取,因此,整体来看,RCFILE相比其余两种格式具有较明显的优势
❷ 数据倾斜解决思路详解
数慎轮据倾斜是由于某个task被分配过多数据,而比其他task需要更多的执行时间(如几十倍,几百倍),培伏导致其他task执行完进入漫长等待的一种现象。
数据倾斜只会发生在多对多或一对多的数据分发的过程中,如spakr的shuffle操作中,在MapRece中的rece阶段,
常见的算子类型为:join,group by 和窗口函数如row_number 。
这是因为这些算子会进行shuffle操作,产生一个key值,如group by的字段,join的on字段,
为了利用多台机器的并发能力,会按这个key值取数范围进行均衡的分发,每台机器尽量分到相同长度的取值范围的key,
然后将这些有key值的数据的数据传输过去。
这时如果某个key范围内的数据量大大多于其他范围的数据量,就会发生数据倾斜。
解决办法:
解决数据倾斜的思路在于,先找到产生数据倾斜的算子操作,然后针对具体的算子,解决它单个key范围被分到过多的数据的问题,
按key的类型,由简便到复杂依次有以下几种解决思路:
1.直接消灭倾斜的key。
2.直接避免shuffle操作,没有了shuffle操作也就没有了数据倾斜
3.通过增多task的数量,减小单个task内的数据量,这个方法适用于某个key范围的数据多的情况。
4.通过特殊处理key值,减小单个task内的数据量,这个方法适用于某些特定的key值的数据过多的情况
第一个解决思路比较简单,找到倾斜的key,直接过滤掉。就没有倾斜问题了。这种操作的适用范围很窄。比如一些空字符串,一些缺省值等等,本身在业务上能接受它们不参与操作。
如果发现造成倾斜的key是这些,就可以直接过滤,非常简单粗暴,性价比最高。
如果该key不能被过滤,就考虑能否将shuffle操作避免掉。
比如join的时候使用广播的方式,将其中一张表广播到所有的机器节点上,这样一个shuffle操作就变成了一个map操作。
广播的方式(map join)适用于join的时候某一张表的数据量比较小的时候,如果两张表都很大,则不适用这种方式。
如果不能避免shuffle操作也不能过滤倾斜的key值,那么我们就要从key值的类型入手,如果倾斜的key值是连续的,不是由单个key值引起的,就可以增大task的数量,
比如,修改shuffle产生的partition参数为更大,就可以使同一个范围内的key值分到不同机器上,
或者使key值重新排列,倒排或者其他方式,使他们不再连续,分配到不同的机器上,就可以防止倾斜。
上述3个操作都比较简单高效,但是应用的场景有限,如果该key不能被过滤,也不能避免shuffle,而且是1个到多个不连续的key引起的,就需要做比较复杂的操作了。配孝携
如果是group by,就可以用两阶段聚合法,
将group by a 改成 group by a,b ,然后再group by a
或者增加一个随机数x,将a通过concat(x,a)改成b,将group by a 改成 group by b, 然后再聚合一次去掉x后的b,group by substr(b,length(x))
如果是join操作,就需要分开join,将倾斜的数据和不倾斜的数据分成两部分。
然后两站表不倾斜的部分join得到第一张表。
倾斜的数据,第一张较大的表:增加一个随机数1-x,随机数取决于你想把数据切成几份。
得到 concat(x,a).
另一张较小的表将每一行复制到x份(总共增加x-1份),然后按顺序标上序号1到x,如下所示:
源数据,倾斜的key值为a和b,
大表:aaaaa bbbbb
小表:aaaa bbbb
原来的join最后得到40条数据. 每个key分到20条
处理过key的表,
大表:1a 2a 2a 1a 2a 1b 2b 3b 3b 2b (增加一个随机数前缀1-3)
小表:
1a 2a 3a 1a 2a 3a 1a 2a 3a 1a 2a 3a 这n条数据都按顺序附加一个1~x的前缀
1b 2b 3b 1b 2b 3b 1b 2b 3b 1b 2b 3b
生成40条数据,每个key平均分到6.66条.
6.66条的计算公式是5/3*4, 5是大表的key的条数,有5个,增加随机数之后,被分成了3份,得到了5/3 条,小表虽然也加了随机数但是复制了x份,
所以小表的key还是4个,所以是:5/3*4
最后将倾斜部分的数据和不倾斜的部分的数据分别join之后再union起来就可以了。
当然,解决数据倾斜的不止这些方法,这些方法只是常用的,本质还是打散集中在某台机器,某个task的的数据量。只要能达到这个目的,就可以。
❸ HIVE优化场景七--数据倾斜--group by 倾斜
HIVE优化场景七--数据倾斜:
GROUP BY 场景下的数据倾斜
JOIN 场景下的数据倾斜
1) 由于空值导致的数据倾斜问题
2) 由于数据类型不一致,导致的转换问题,导致的数据睁族缓倾斜
3) 业务数据本身分布不均,导致的数据倾斜,下面4个小场景
i.大表与小表JOIN (Map JOIN)
ii.大表与大表JOIN, 一张表数据分布均匀,另一张表数据特定的KEY(有限几个) 分布不均
iii.大表与大表JOIN, 一张表数据分布均匀,另一张表大量的KEY 分布不均
iiii.大表与大表JOIN, 桶表,进行表拆分
group by 场景下的其实比较简单,我们只需要在 HIVE 中设置如下两个参数即可 :
set hive.map.aggr=true;
set hive.groupby.skewindata=true;
我们看下,设置这两个参数为什么能解决 GROUP BY 的数据倾斜问题
set hive.map.aggr=true; (默认 : true) 第一个参数表示在 Map 端进行预聚。 因为传到数据量小了,所以效率高了,可以缓解数据倾斜问题。
最主要的参数,其实是 set hive.groupby.skewindata=true;
这个参数有什么作穗渣用呢。这场来说 GROUP BY 流程只会产生一个MR JOB。但是,设置这个参数为 true 以后, 原来 GROUP BY 的 MR JOB 会由原来的一个变为两个。
流程如下:
JOB1 .第一个作业会进行预处理,将数据进行预聚合,并随机分发到 不同的 Recer 中。
Map流程悉模 : 会生成两个job来执行group by,第一个job中,各个map是平均读取分片的,在map阶段对这个分片中的数据根据group by 的key进行局部聚合操作,这里就相当于Combiner操作。
Shuffle流程:在第一次的job中,map输出的结果随机分区,这样就可以平均分到rece中
Rece流程: 在第一次的job中,rece中按照group by的key进行分组后聚合,这样就在各个rece中又进行了一次局部的聚合。
JOB2.读取上一个阶段MR的输出作为Map输入,并局部聚合。按照key分区,将数据分发到 Rece 中,进行统计。
Map流程 : 因为第一个job中分区是随机的,所有rece结果的数据的key也是随机的,所以第二个job的map读取的数据也是随机的key,所以第二个map中不存在数据倾斜的问题。
在第二个job的map中,也会进行一次局部聚合。
Shuffle流程 : 第二个job中分区是按照group by的key分区的,这个地方就保证了整体的group by没有问题,相同的key分到了同一个rece中。
Rece流程 :经过前面几个聚合的局部聚合,这个时候的数据量已经大大减少了,在最后一个rece里进行最后的整体聚合。
SQL:
SELECT
pt,COUNT(1)
FROM datacube_salary_org
GROUP BY pt
;
开启前
STAGE DEPENDENCIES:
Stage-1 is a root stage
Stage-0 depends on stages: Stage-1
STAGE PLANS:
Stage: Stage-1
Map Rece
Map Operator Tree:
TableScan
alias: datacube_salary_org
Statistics: Num rows: 7 Data size: 1628 Basic stats: COMPLETE Column stats: COMPLETE
Select Operator
expressions: pt (type: string)
outputColumnNames: pt
Statistics: Num rows: 7 Data size: 1628 Basic stats: COMPLETE Column stats: COMPLETE
Group By Operator
aggregations: count(1)
keys: pt (type: string)
mode: hash
outputColumnNames: _col0, _col1
Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE
Rece Output Operator
key expressions: _col0 (type: string)
sort order: +
Map-rece partition columns: _col0 (type: string)
Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE
value expressions: _col1 (type: bigint)
Rece Operator Tree:
Group By Operator
aggregations: count(VALUE._col0)
keys: KEY._col0 (type: string)
mode: mergepartial
outputColumnNames: _col0, _col1
Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE
File Output Operator
compressed: false
Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
Stage: Stage-0
Fetch Operator
limit: -1
Processor Tree:
ListSink
开启后:
STAGE DEPENDENCIES:
Stage-1 is a root stage
Stage-2 depends on stages: Stage-1
Stage-0 depends on stages: Stage-2
STAGE PLANS:
Stage: Stage-1
Map Rece
Map Operator Tree:
TableScan
alias: datacube_salary_org
Statistics: Num rows: 7 Data size: 1628 Basic stats: COMPLETE Column stats: COMPLETE
Select Operator
expressions: pt (type: string)
outputColumnNames: pt
Statistics: Num rows: 7 Data size: 1628 Basic stats: COMPLETE Column stats: COMPLETE
Group By Operator
aggregations: count(1)
keys: pt (type: string)
mode: hash
outputColumnNames: _col0, _col1
Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE
Rece Output Operator
key expressions: _col0 (type: string)
sort order: +
Map-rece partition columns: rand() (type: double)
Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE
value expressions: _col1 (type: bigint)
Rece Operator Tree:
Group By Operator
aggregations: count(VALUE._col0)
keys: KEY._col0 (type: string)
mode: partials
outputColumnNames: _col0, _col1
Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE
File Output Operator
compressed: false
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazybinary.LazyBinarySerDe
Stage: Stage-2
Map Rece
Map Operator Tree:
TableScan
Rece Output Operator
key expressions: _col0 (type: string)
sort order: +
Map-rece partition columns: _col0 (type: string)
Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE
value expressions: _col1 (type: bigint)
Rece Operator Tree:
Group By Operator
aggregations: count(VALUE._col0)
keys: KEY._col0 (type: string)
mode: final
outputColumnNames: _col0, _col1
Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE
File Output Operator
compressed: false
Statistics: Num rows: 3 Data size: 576 Basic stats: COMPLETE Column stats: COMPLETE
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
Stage: Stage-0
Fetch Operator
limit: -1
Processor Tree:
ListSink
可以明显的看到开启优化后。增加了一层 JOB
❹ 数据倾斜(一):数据倾斜及具体场景
相信大部分做数据的童鞋们都会遇到数据倾斜,数卖首据倾斜会发生在数据开发的各个环节中,比如:
1.用Hive算数据的时候rece阶段卡在99.99%
2.用SparkStreaming做实时算法时候,一直会有executor出现OOM的错误,但是其余的executor内存使用率却很低。
3.这些问题经常会困扰我们,辛辛苦苦等了几个小时的数据就是跑不出来,心里多难过啊。
为什么要突出这么大数据量?先说一下笔者自己最初对数据量的理解:
数据量大就了不起了?数据量少,机器也少,计算能力也是有限的,因此难度也是一样的。凭什么数据量大就会有数据倾斜,数据量小就没有?
这样理解也有道理,但是比较片面,举两个场景来对比:
公司一:总用户量1000万,5台64G内存的的服务器。
公司二:总用户量10亿,1000台64G内存的服务器。
两个公司都部署了Hadoop集群。假设现在遇到了数据倾斜,发生什么?
1.公司一的数据分析师在做join的时候发生了数据倾斜,会导致有几百万用户的相关数据集中到了一台服务器上,几百万的用户数据,说大也不大,正常字段量的数据的话64G还是能轻松处理掉的。
2.公司二的数据分析师在做join的时候也发生了数据倾斜,可能会有1个亿的用户相关数据集中到了一台机器上了(相信我,这很常坦核见)。这时候一台机器就很难搞定了,最后会很难算出结果。
下面会分几个场景来描述一下数据倾斜的特征,方便读者辨别。由于Hadoop和Spark是最常见的两个计算平台,下面就以这两个平台说明。
Hadoop中直接贴近用户使用使用的时Maprece程序和Hive程序,虽说Hive最后也是用MR来执行(至少目前Hive内存计算并不普及),但是毕竟写的内容逻辑区别很大,一个是程序,一个是Sql,因此这里稍作区分。
具体表现:
Hadoop中的数据倾斜主要表现在: Rece阶段卡在99.99%,一直不能结束。
这里如果详细的看日志或者和监控界面的话会发现:
Spark中的数据倾斜也让配掘很常见,这里包括Spark Streaming和Spark Sql,表现主要有下面几种:
❺ hive数据倾斜及处理
火山日常啰嗦
学习了一些大数据的相关框架后,发现应用层的东西确实不难,真正难的都是底层原理,所以我查看了很多资料,借鉴了前人的方法再加上自己的理解,写下了这篇文章。
数据倾斜的直白概念:
数据倾斜就是数据的分布不平衡,某些地方特别多,某些地方又特别少,导致的在处理数据的时候,有些很快就处理完了,而有些又迟迟未能处理完,导致整体任务最终迟迟无法完成,这种现象就是数据倾斜。
针对maprece的过程来说就是,有多个rece,其中有一个或者若干个rece要处理的数据量特别大,而其他的rece处理的数据量则比较小,那么这些数据量小的rece很快就可以完成,而数据量大的则需要很多时间,导致整个任务一直在等它而迟迟无法完成。
跑mr任务时常见行散巧的rece的进度总是卡在99%,这种现象很大可能就是数据倾斜造成的。
产生数据倾斜的原因:
1) key的分布不均匀或者说某些key太集中。
上面就说过,rece的数据量大小差异过大,而rece的数据是分区的结掘尺果,分区是对key求hash值,根据hash值决定该key被分到某个分区,进而进入到某个rece,而如果key很集中或者相同,那么计算得到它们的hash值可能一样,那么就会被分配到同一个rece,就会造成这个rece所要处理的数据量过大。
2) 业务数据自身的特性。
比如某些业务数据作为key的字段本就很集中,那么结果肯定会导致数据倾斜啊。
还有其他的一些原因,但是,根本原因还是key的分布不均匀,而其他的原因就是会造成key不均匀,进而导致数据倾斜的后果,所以说根本原因是key的分布不均匀。
既然有数据倾斜这种现象,就必须要有数据倾斜对应的处理方案啊。
简单地说数据倾斜这种现象导致的任务迟迟不能完成,耗费了太多时间,极大地影响了性能,所以我们数据倾斜的解决方案档键设计思路就是往如何提高性能,即如何缩短任务的处理时间这方面考虑的,而要提高性能,就要让key分布相对均衡,所以我们的终极目标就是考虑如何预处理数据才能够使得它的key分布均匀。
常见的数据倾斜处理方案:
1 设置参数
1)设置hive.map.aggr=true //开启map端部分聚合功能,就是将key相同的归到一起,减少数据量,这样就可以相对地减少进入rece的数据量,在一定程度上可以提高性能,当然,如果数据的减少量微乎其微,那对性能的影响几乎没啥变化。
2)设置hive.groupby.skewindata=true //如果发生了数据倾斜就可以通过它来进行负载均衡。当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Rece 中,每个 Rece 做部分聚合操作,并输出结果,这样处理的结果是相同的Key 有可能被分发到不同的 Rece 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照Key 分布到 Rece 中(这个过程是按照key的hash值进行分区的,不同于mr job1的随机分配,这次可以保证相同的Key 被分布到同一个 Rece 中),最后完成最终的聚合操作。所以它主要就是先通过第一个mr job将key随机分配到rece,使得会造成数据倾斜的key可能被分配到不同的rece上,从而达到负载均衡的目的。到第二个mr job中,因为第一个mr job已经在rece中对这些数据进行了部分聚合(就像单词统计的例子,a这个字母在不同的rece中,已经算出它在每个rece中的个数,但是最终的总的个数还没算出来,那么就将它传到第二个mr job,这样就可以得到总的单词个数),所以这里直接进行最后的聚合就可以了。
3)hive.exec.recers.bytes.per.recer=1000000000 (单位是字节)
每个rece能够处理的数据量大小,默认是1G
4)hive.exec.recers.max=999
最大可以开启的rece个数,默认是999个
在只配了hive.exec.recers.bytes.per.recer以及hive.exec.recers.max的情况下,实际的rece个数会根据实际的数据总量/每个rece处理的数据量来决定。
5)mapred.rece.tasks=-1
实际运行的rece个数,默认是-1,可以认为指定,但是如果认为在此指定了,那么就不会通过实际的总数据量/hive.exec.recers.bytes.per.recer来决定rece的个数了。
2 sql语句优化
给几个具体的场景以及在这些场景下的处理方案:
1)进行表的join这种业务操作时,经常会产生数据倾斜。
原因就是这些业务数据本就存在key会分布不均匀的风险,所以我们join时不能使用普通的join(rece端join)或者可以使用普通join,但是是优化后的。
但是这种操作有个前提条件就是仅适用于小表join大表,而小表怎么定义它的大小,多小的表才算小表,这里有个参数可以确定的(但是这个参数名我暂时忘记了),如果小表的数据大小小于这个值,就可以使用map join,而是在这种情况下是自动使用map join这种方案的。所以如果是大小表join,直接用map join,避免数据倾斜。
方法1:(普通join)
select * from log a join users b on (a.user_id is not null and a.user_id = b.user_id );
这是属于表的内连接的,两张表不满足条件的记录都不保留。
方法2:检测到user_id是null时给它赋予一个新值(这个新值由一个字符串(比如我自己给它定一个 hive)加上一个随机数组成),这样就可以将原来集中的key分散开来,也避免了数据倾斜的风险。而且因为这些数据本来就是无效数据,根本不会出现在结果表中,所以,这样处理user_id(由一个字符串(比如我自己给它定一个 hive)加上一个随机数),它也无法关联的,因为有效的数据的user_id没有这种形式的,所以就算这些无效数据出现在不同的rece中还是不会影响结果的,我这样处理只是为了将它们分散开而已,所以用这种方法处理,结果表中也不会出现null这些无效数据,跟过滤处理方案得到的结果是一样的。(普通join)
select *
from log a
join users b
on case when a.user_id is null then concat(‘hive’,rand() ) else a.user_id end = b.user_id;
但是这两种方案只是适用于大表join大表的内连接,两张表的无效数据都不保留。
但是如果对于左外连接或者右外连接这种情况,即使驱动表中某些记录在另一张表中没有数据与它对应,但我们是依然需要保留驱动表的这些数据的,那该怎么办呢?其实很简单,只需要将上述方法得到的结果再与驱动表的这些无数据取并集就可以了。
如下:
select * from log a
left outer join users b
on a.user_id is not null
and a.user_id = b.user_id
union all
select * from log a
where a.user_id is null;
2)虽然都是大表,但是呢对于某些业务数据而言,其有用的部分只占它所在表的很少一部分,那么我们就可以将它们先取出来,得到的结果应该是一张小表,那么就可以使用map join来避免数据倾斜了。
场景:用户表中user_id字段为int,log表中user_id字段既有string类型也有int类型。
当按照user_id进行两个表的Join操作时,因为我们在连接时要进行user_id的比较,所以需要user_id的类型都相同,如果我们选择将log表中的String类型转换为int类型,那么就可能会出现这种情况:String类型转换为int类型得到的都是null值(这就是类型转换的问题了,String类型数据转换为int类型会失败,数据丢失,就会赋null值),如果所有的String类型的user_id都变成了null,那么就又出现了集中的key,分区后就又会导致数据倾斜。所以我们进行类型转换时不能选择将String类型转换为int,而应该将int类型转换为String,因为int转换为String不会出问题,int类型原来的值是什么,转换为String后对应的字符串就会是什么,形式没变,只是类型变了而已。
解决方法:把int类型转换成字符串类型
select * from users a
join logs b
on (a.usr_id = cast(b.user_id as string));
比如有一份日志,要你从日志中统计某天有多少个用户访问网站,即统计有多少个不同的user_id;但是呢这个网站却又恰巧遭到攻击,日志中大部分都是同一个user_id的记录,其他的user_id属于正常访问,访问量不会很大,在这种情况下,当你直接使用count(distinct user_id)时,这也是要跑mr任务的啊,这时这些大量的相同的user_id就是集中的key了,结果就是通过分区它们都被分到一个rece中,就会造成这个rece处理的数据特别大,而其中的rece处理的数据都很小,所以就会造成数据倾斜。
那么要怎么优化呢?
方法1:可以先找出这个user_id是什么,过滤掉它,然后通过count(distinct user_id)计算出剩余的那些user_id的个数,最后再加1(这1个就是那个被过滤掉的user_id,虽然它有大量的记录,但是ser_id相同的都是同一个用户,而我们要计算的就是用户数)
sql语句展示:
分组求和后降序排序,就可以得到这个数据量最大的user_id是什么,然后我们下一步操作时就过滤它,等计算完其他的再加上它这一个。
select user_id,count(user_id) from log group by user_id desc limit 2;
select count(distinct user_id)+1 as sum from log;
sum就是最终的结果--用户数
方法2:我们可以先通过group by分组,然后再在分组得到的结果的基础之上进行count
sql语句展示:
select count(*) from (select user_id from log group by user_id) new_log;
总的来说就是,数据倾斜的根源是key分布不均匀,所以应对方案要么是从源头解决(不让数据分区,直接在map端搞定),要么就是在分区时将这些集中却无效的key过滤(清洗)掉,或者是想办法将这些key打乱,让它们进入到不同的rece中。
性能调优是指通过调整使得机器处理任务的速度更快,所花的时间更少,而数据倾斜的处理是hive性能调优的一部分,通过处理能够大大减少任务的运行时间。
除了数据倾斜的处理之外,hive的优化还有其他方面的,例如where子句优化:
select * from a left outer join b on (a.key=b.key) where a.date='2017-07-11' and b.date='2017-07-11';
这是一个左外连接。
这个sql语句执行的结果是:得到的结果是表a与表b的连接表,且表中的记录的date都是'2017-07-11'。
而这个sql语句的执行过程是:逐条获取到a表的记录,然后扫描b表,寻找字段key值为a.key的记录,找到后将b表的这条记录连接到a表上,然后判断连接后的这条记录是否满足条件a.date='2017-07-11' and b.date='2017-07-11',如果满足,则显示,否则,丢弃。
因为这是一个左外连接,且a为驱动表,连接时在a中发现key而在b中没有发现与之相等的key时,b中的列将置为null,包括列date,一个不为null,一个为null,这样后边的where就没有用了。
简答的说这个方案的做法就是先按连接条件进行连接,连接后再看where条件,如果不满足就丢弃,那之前连接所做的那些功夫就浪费了,白白耗费了资源(cpu等),增加了运行的总时间,如果有一种方案可以在未进行连接之前就直接判断出不满足最终的条件,那么就可以直接丢弃它,这样对于这样的记录就不要浪费资源以及时间去连接了,这样也是能提升性能的,下面就看看这种方案:
sql语句:
将刚才的where限制条件直接放到on里面,那么就变成了满足这三个条件才会进行连接,不满足的直接过滤掉,就像上面所说的,少了无效连接那一步,就相对地节约了时间,如果这样的无效连接的记录很多的话,那么采用这种改进版的方案无疑能够较大程度地提高性能。
select * from a left outer join b on (a.key=b.key and a.date='2017-07-11' and b.date='2017-07-11');
不管怎么说,我们在运行任务时,总是希望能加快运行速度,缩短运行时间,更快地得到结果,即提升性能,这是我们的目的,这就是我们所谓的性能调优。
关于小表join大表的补充:
表join时的操作是这样的:
当操作到驱动表的某条记录时,就会全局扫描另一张表,寻找满足条件的记录,而当扫描它时,为了读取速度更快,一般都选先将它加载到内存,而内存的大小是有限的,为了不占据过多的内存或者避免内存溢出,加载进入内存的表一般是小表,即数据量比较小,map join就是这样做的。
即驱动表不放进内存,而另一张表(即要连接到驱动表的那一张表)就要先加载进内存,为了扫描速度更快,提高性能。
比如select * from a left outer join b on (a.key=b.key);
左外连接,驱动表是a,表b的记录是要被连接到表a的,所以每在a上连接一条记录就要被全局扫描一次的表是b,所以表b应先加载到内存(前提是表b是小表,如果是大表的话,估计会产生oom异常--out of memory内存溢出异常)。
select * from aa right outer join bb on (a.key=b.key);
右外连接,驱动表是bb,aa应先加载到内存(前提是小表)。
ps:希望我的分享能帮助到有需要的伙伴哦。我不是大神的哦,如果文中有误,还请大家不吝赐教,帮忙指正,谢谢了!!!
❻ 几种数据倾斜的情况,并解释为什么会倾斜,以及如何解决
Mapjoin是一种避免避免数据倾斜的手段
允许在map阶段进行join操作,MapJoin把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配,由于在map是进行了join操作,省去了rece运行的效率也会高很多
在《hive:join遇到问题》有具体操作
在对多个表join连接操作时,将小表放在join的左边,大表放在Jion的右边,
在执行中仿敬这样的join连接时小表中的数据会被缓存到内存当中,这样可以有效减少发生内存溢出错误的几率
2. 设置参数
hive.map.aggr = true
hive.groupby.skewindata=true 还有其他参数
3.SQL语言调节
比如: group by维度过小时:采大滑用sum() group by的方式来替换count(distinct)完成计算
4.StreamTable
将在recer中进行join操作时的小卖慎table放入内存,而大table通过stream方式读取
❼ 数据仓库面试题
一般数据仓库面试会面两轮,第一轮一般是sql技术面,第二轮就是 维度建模 和 数据治理 的问题。
一轮技术面(待补充):
1、数据倾斜:
数据倾斜一般产生的原因是数据在map端hash分配到rece端时,某一个key的数量远大于其他的key,导致某一个rece的处理时间较长。
1)key分布不均匀
2)数据本身就是如此
3)数据关联时没有把握好关联键
解决方案
1)参数调整:hive.map.aggr = true;hive.groupby.skewindata=true;
当存在数据倾斜时开启负载均衡,此时会生成两个MapRece任务,第一个MR任务会将map端产生的key随机的分配到rece,先进行一次聚合,第二个MR任务会将第一个任务的预处理结果作为输入,将相同的key分配到同一个rece当中。
2)sql调整:在处理大量空值导致数据倾斜的情况下,可以先将空值附一个特殊值去处理,比如给一个随机数加字符串的方式,因为空值数据是关联不上的,不会影响后期处理。
2、order by,sort by,cluster by,distribute by的区别
1)order by是全局排序,排序过程在一个rece中进行,在数据量较大时就会很慢
2)sort by是局部排序,排序结果在同一个rece中使有序的
3)distribute by是将数据按照字段划分到一个rece中,一般与sort by连用进行分组排序的作用
4)cluster by除具有distribute by功能外慎首滑还具有sort by的功能
order by优化(阿里面试):
1)开启严格模式,order by之后添加limit子句
2)利用sort by,在每个rece中先排序取出top项,再把预处理结果order by输出
3、hive中内部表和外部表的区别
1)在创建表的时候,内部表是将数据移动到数据仓库指向的路径,外部表仅记录数据所在的路径,不对数据的位置做任何改变。
2)在删除表的时候,内部表会将元数据和数据都删除,外部表只删除元芹升数据。
4、列转行、行转列
1)列转行:lateral view explode(split('column_name',','))作为宽腊一个新表
2)行转列:concat_ws(',',collect_set(column_name))
5、maprece运行原理
6、数据仓库分层原理(阿里面试)
7、维度建模中三种事实表的应用场景(阿里面试)
二轮面试(待补充)