本博客仅作学习记录所用,基于尚硅谷和黑马程序员做的笔记…
Hive学习笔记1
Hive学习笔记2
为了支持多种压缩/解压缩算法,Hadoop 引入了编码/解码器,如下表所示:
压缩性能的比较:
http://google.github.io/snappy/
On a single core of a Core i7 processor in 64-bit mode, Snappy compresses at about 250
MB/sec or more and decompresses at about 500 MB/sec or more.
(在64位模式下的core i7处理器单核上,Snappy的压缩率约为250MB/秒或更多,解压速度大约为500 MB/秒或更多。)
返回顶部
要在 Hadoop 中启用压缩,可以配置如下参数(mapred-site.xml 文件中):
开启 map 输出阶段压缩可以减少 job 中 map 和 Reduce task 间数据传输量。具体配置如下:
hive (default)>set hive.exec.compress.intermediate=true;
hive (default)>set mapreduce.map.output.compress=true;
hive (default)>set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;
hive (default)> select count(ename) name from emp;
hadoop103:8088
查看历史任务日志:当 Hive 将 输 出 写 入 到 表 中 时 , 输出内容同样可以进行压缩。属性hive.exec.compress.output控制着这个功能。用户可能需要保持默认设置文件中的默认值false,这样默认的输出就是非压缩的纯文本文件了。用户可以通过在查询语句或执行脚本中设置这个值为 true,来开启输出结果压缩功能。
hive (default)>set hive.exec.compress.output=true;
hive (default)>set mapreduce.output.fileoutputformat.compress=true;
hive (default)> set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;
hive (default)> set mapreduce.output.fileoutputformat.compress.type=BLOCK;
hive (default)> insert overwrite local directory
'/opt/module/data/distribute-result' select * from emp distribute by
deptno sort by empno desc;
Hive 支持的存储数据的格式主要有:TEXTFILE
(默认) 、SEQUENCEFILE
、ORC
、PARQUET
。
如图所示左边为逻辑表,右边第一个为行式存储,第二个为列式存储。
TEXTFILE 和 SEQUENCEFILE
的存储格式都是基于行式存储
的;ORC 和 PARQUET
是基于列式存储
的。
返回顶部
默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合 Gzip、Bzip2 使用,
但使用 Gzip 这种方式,hive 不会对数据进行切分,从而无法对数据进行并行操作
。
Orc (Optimized Row Columnar)是 Hive 0.11 版里引入的新的存储格式。
如下图所示可以看到每个 Orc 文件由 1 个或多个 stripe 组成,每个 stripe 一般为 HDFS的块大小,每一个 stripe 包含多条记录,这些记录按照列进行独立存储,对应到 Parquet中的 row group 的概念。每个 Stripe 里有三部分组成,分别是 Index Data,Row Data,Stripe Footer:
Index Data
:一个轻量级的 index,默认是每隔 1W 行做一个索引。Index data包含每列的最大和最小值以及每列所在的行位置。行索引里面提供了偏移量,它可以跳到正确的压缩块位置。Row Data
:存的是具体的数据,先取部分行,然后对这些行按列进行存储。对每个列进行了编码,分成多个 Stream 来存储。Stripe Footer
:存的是各个 Stream 的类型,长度等信息。使用ORC文件格式时,用户可以使用HDFS的每一个block存储ORC文件的一个stripe。对于一个ORC文件来说,stripe的大小一般需要设置得比HDFS的block小,如果不这样的话,一个stripe就会分别在HDFS的多个block上,当读取这种数据时就会发生远程读数据的行为。如果设置stripe的只保存在一个block上的话,如果当前block上的剩余空间不足以存储下一个strpie,ORC的writer接下来会将数据打散保存在block剩余的空间上,直到这个block存满为止。这样,下一个stripe又会从下一个block开始存储。
返回顶部
Parquet 文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此 Parquet 格式文件是自解析的。
行组(Row Group)
:每一个行组包含一定的行数,在一个 HDFS 文件中至少存储一个行组,类似于 orc 的 stripe 的概念。列块(Column Chunk)
:在一个行组中每一列保存在一个列块中,行组中的所有列连续的存储在这个行组文件中。一个列块中的值都是相同类型的,不同的列块可能使用不同的算法进行压缩。页(Page)
:每一个列块划分为多个页,一个页是最小的编码的单位,在同一个列块的不同页可能使用不同的编码方式。返回顶部
从存储文件的压缩比和查询速度两个角度对比。
[hyj@hadoop102 datas]$ vim log.data
2017-08-10 13:00:00 http://www.taobao.com/17/?tracker_u=1624169&type=1 B58W48U4WKZCJ5D1T3Z9ZY88RU7QA7B1 http://hao.360.cn/ 1.196.34.243 NULL -1
2017-08-10 13:00:00 http://www.taobao.com/item/962967_14?ref=1_1_52_search.ctg_1 T82C9WBFB1N8EW14YF2E2GY8AC9K5M5P http://www.yihaodian.com/ctg/s2/c24566-%E5%B1%B1%E6%A5%82%E5%88%B6%E5%93%81?ref=pms_15_78_258 222.78.246.228 134939954 156
2017-08-10 13:00:00 http://www.taobao.com/1/?tracker_u=1013304189&uid=2687512&type=3 W17C89RU8DZ6NMN7JD2ZCBDMX1CQVZ1W http://www.yihaodian.com/1/?tracker_u=1013304189&uid=2687512&type=3 118.205.0.18 NULL -20
2017-08-10 13:00:00 http://m.taobao.com/getCategoryByRootCategoryId_1_5146 f55598cafba346eb217ff3fbd0de2930 http://m.yihaodian.com/getCategoryByRootCategoryId_1_5135 10.4.6.53 NULL -1000
2017-08-10 13:00:00 http://m.taobao.com/getCategoryByRootCategoryId_1_24728 f55598cafba346eb217ff3fbd0de2930 http://m.yihaodian.com/getCategoryByRootCategoryId_1_5146 10.4.4.109 NULL -1000
2017-08-10 13:00:00 http://union.taobao.com/link_make/viewPicInfo.do?imgSize=660x70&truckerU=101542127 4PBTT18JEEJHM91DNGKNUSZTA29W8WP3 http://www.jintoutiao.com/yule.html 125.38.159.84 NULL -30
2017-08-10 13:00:00 http://www.taobao.com/item/9680587_1?smt_b=C0B0A09BECBF110A470F00C 615MMAA5RFVRRMHJVP5VCHTQGEGDW988 211.167.237.134 NULL -20
2017-08-10 13:00:00 http://union.taobao.com/link_make/viewPicInfo.do?imgSize=660x70&truckerU=101542127 QCU8A6VCNX28YGGJVQAABG4BJ6F8QT1B http://jintoutiao.com/yule.html 117.22.144.64 NULL 327
2017-08-10 13:00:00 http://www.taobao.com/ctg/s2/c8325-%E7%99%BE%E6%B4%81%E5%B8%83-%E9%92%A2%E4%B8%9D%E7%90%83/ ZYVF5W5WDFGAQP1S45RTFR7SPVM8GY5Q http://www.yihaodian.com/item/user/continueShopping.do?lc=\u6c34\u4e0a\u7528\u5177&csps=1984887_3_1_950411&pageType=B 61.128.247.131 5305018 -40
2017-08-10 13:00:00 http://m.taobao.com/getProductDetail_1_1001417 A90A3460D49D437E96BC3B4DC138B628 http://m.yihaodian.com/searchProduct_1_银杏洗面奶_2 222.128.241.1 NULL -20
2017-08-10 13:00:00 http://search.taobao.com/s2/c0-0/k%25E6%25B4%2597%25E5%258F%2591%25E6%25B0%25B4/ WGSMFJD42BQEYB57EUHPUHHZMZHJTGX2 http://www.yihaodian.com/3/?type=3&tracker_u=1013241403 60.30.93.90 NULL -30
2017-08-10 13:00:00 http://m.taobao.com/ RJSDGJVTMNBHXE9HX53ZTZTV11NCYTED 58.39.59.80 NULL -10
create table log_text (
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as textfile;
(2)向表中加载数据
load data local inpath '/opt/module/hive-3.1.2/datas/log.data' into table log_text ;
(3)查看表中数据大小
dfs -du -h /user/hive/warehouse/log_text;
18.1 M 54.4 M /user/hive/warehouse/log_text/log.data
或
create table log_orc(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as orc
tblproperties("orc.compress"="NONE"); -- 设置 orc 存储不使用压缩
(2)向表中加载数据(不能使用load命令)
insert into table log_orc select * from log_text;
(3)查看表中数据大小
dfs -du -h /user/hive/warehouse/log_orc;
7.7 M 23.1 M /user/hive/warehouse/log_orc/000000_0
create table log_parquet(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as parquet;
(2)向表中加载数据(不能使用load命令)
insert into table log_parquet select * from log_text;
(3)查看表中数据大小
dfs -du -h /user/hive/warehouse/log_parquet;
13.1 M 39.3 M /user/hive/warehouse/log_parquet/000000_0
insert overwrite local directory
'/opt/module/data/log_text' select substring(url,1,4) from log_text;
insert overwrite local directory
'/opt/module/data/log_orc' select substring(url,1,4) from log_orc;
insert overwrite local directory
'/opt/module/data/log_parquet' select substring(url,1,4) from log_parquet;
返回顶部
官网:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ORC
ORC 存储方式的压缩:
注意:所有关于 ORCFile 的参数都是在 HQL 语句的 TBLPROPERTIES 字段里面出现
create table log_orc_zlib(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as orc
tblproperties("orc.compress"="ZLIB");
insert into log_orc_zlib select * from log_text;
dfs -du -h /user/hive/warehouse/log_orc_zlib/;
2.8 M 8.3 M /user/hive/warehouse/log_orc_zlib/000000_0
create table log_orc_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as orc
tblproperties("orc.compress"="SNAPPY");
insert into log_orc_snappy select * from log_text;
dfs -du -h /user/hive/warehouse/log_orc_snappy/;
3.7 M 11.2 M /user/hive/warehouse/log_orc_snappy/000000_0
ZLIB 比 Snappy 压缩的还小。原因是 ZLIB 采用的是 deflate 压缩算法。比 snappy 压缩的压缩率高。
create table log_parquet_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
row format delimited fields terminated by '\t'
stored as parquet
tblproperties("parquet.compression"="SNAPPY");
insert into log_parquet_snappy select * from log_text;
dfs -du -h /user/hive/warehouse/log_parquet_snappy;
6.4 M 19.2 M /user/hive/warehouse/log_parquet_snappy/000000_0
返回顶部
EXPLAIN [FORMATTED|EXTENDED|DEPENDENCY|AUTHORIZATION|] query
返回JSON格式的执行计划
返回更加详细的执行计划
返回查询所依赖的表和分区的列表
列出需要被授权的条目,包括输入与输出
explain select count(*) as cnt from tb_emp where deptno = '10';
explain
select
deptno,count(*) as cnt
from tb_emp where salary > 2000
group by deptno order by cnt desc;
explain select deptno, avg(sal) avg_sal from emp group by deptno having avg_sal > 2000;
Explain |
--------------------------------------------------------------------------------------------------+
STAGE DEPENDENCIES: |
Stage-1 is a root stage |
Stage-0 depends on stages: Stage-1
|
#stage -1是根阶段,stage -0在stage -1完成后执行(stage -0依赖于stage -1)
|
STAGE PLANS: |
Stage: Stage-1 |
Map Reduce |
Map Operator Tree: #Map操作 |
TableScan #表扫描 |
alias: emp #alias:表名称
#Statistics:表统计信息,包含表中数据条数,数据大小等 |
Statistics: Num rows: 1 Data size: 6610 Basic stats: COMPLETE Column stats: NONE |
Select Operator #选取操作
#expressions:需要的字段名称及字段类型
expressions: sal (type: double), deptno (type: int)
#输出的列名称
outputColumnNames: sal, deptno |
Statistics: Num rows: 1 Data size: 6610 Basic stats: COMPLETE Column stats: NONE |
Group By Operator #分组聚合操作 |
aggregations: avg(sal) #aggregations显示聚合函数信息 |
keys: deptno (type: int) #分组的字段 |
mode: hash #mode:聚合模式,hash表示随机聚合,partial局部聚合,final最终聚合
#聚合之后输出列名
outputColumnNames: _col0, _col1
#表统计信息(预估),包含分组聚合之后的数据条数,数据大小等
Statistics: Num rows: 1 Data size: 6610 Basic stats: COMPLETE Column stats: NONE |
Reduce Output Operator #输出到reduce操作 (Map操作将数据输出到reduce,并没有开始做reduce) |
# 在Map阶段和Reduce阶段输出的都是键值对的形式
# key expressions:Map阶段输出的键(key)所用的数据列
key expressions: _col0 (type: int) # |
sort order: + #分区排序,sort order值为空不排序;值为+升序排序;值为-降序排序;值为±排序的列为两列,第一列为升序,第二列为降序 |
#Map阶段输出到Reduce阶段的分区列
Map-reduce partition columns: _col0 (type: int) |
Statistics: Num rows: 1 Data size: 6610 Basic stats: COMPLETE Column stats: NONE|
#value expressions:Map阶段输出的值(value)所用的数据列
value expressions: _col1 (type: struct<count:bigint,sum:double,input:double>) |
Execution mode: vectorized #向量化模式,每次处理数据时会将1024行数据组成一个batch进行处理,而不是一行一行进行处理,显著提高执行速度 |
Reduce Operator Tree: #Reduce操作 |
Group By Operator #分组聚合操作 |
aggregations: avg(VALUE._col0) |
keys: KEY._col0 (type: int) |
mode: mergepartial #mergepartial合并多个Map的输出 若是complete完全模式,则表示Map端没有进行聚合 |
outputColumnNames: _col0, _col1 #聚合之后输出列名 |
Statistics: Num rows: 1 Data size: 6610 Basic stats: COMPLETE Column stats: NONE |
Filter Operator #过滤操作
#predicate:过滤条件
predicate: (_col1 > 2000.0D) (type: boolean) |
Statistics: Num rows: 1 Data size: 6610 Basic stats: COMPLETE Column stats: NONE |
File Output Operator #文件输出操作(Reduce端的输出,输出为一个临时文件) |
compressed: false #是否压缩 |
Statistics: Num rows: 1 Data size: 6610 Basic stats: COMPLETE Column stats: NONE |
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 #-1表示不限制条数,其它值为限制的条数 |
Processor Tree: |
ListSink |
|
默认设置了hive.map.aggr=true(提高聚合的性能,这个设置会触发在map阶段做部分聚合),
所以会在mapper端先group by一次,最后再把结果merge(合并)起来,为了减少reducer处理的数据量。
如果把hive.mao.aggr=false,那将group by放到reducer才做。
Group By任务转化为MR任务的流程如下:
Map:生成键值对,以GROUP BY条件中的列作为Key,以聚集函数的结果作为Value
Shuffle:根据Key的值进行 Hash,按照Hash值将键值对发送至不同的Reducer中
Reduce:根据SELECT子句的列以及聚集函数进行Reduce
参考链接:Hive执行计划分析之group by执行计划分析
--A:
explain select e.*,d.* from emp e,dept d where e.deptno =d.deptno;
--B:
explain select * from emp e cross join dept d on e.deptno =d.deptno;
explain select * from emp e cross join dept d where e.deptno =d.deptno;
--可以发现这3条查询语句的执行计划是一样的
Explain |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
STAGE DEPENDENCIES: |
Stage-4 is a root stage |
Stage-3 depends on stages: Stage-4 |
Stage-0 depends on stages: Stage-3 |
#stage -4是根阶段,stage -3在stage -4完成后执行,stage -0在stage -3完成后执行。
|
STAGE PLANS: |
Stage: Stage-4 |
#本地化的MapReduce:因为测试表的数据量非常小,所以Hive最终选择将数据拉取到本地直接操作,而不是去执行一个完整的分布式MapReduce
Map Reduce Local Work |
Alias -> Map Local Tables: |
$hdt$_1:d |
Fetch Operator |
limit: -1 |
Alias -> Map Local Operator Tree: |
$hdt$_1:d |
TableScan #表扫描 |
alias: d # alias:别名
#Statistics:表统计信息(预估),包含表中数据条数,数据大小等 |
Statistics: Num rows: 1 Data size: 730 Basic stats: COMPLETE Column stats: NONE
Filter Operator #过滤操作(join时null值不能关联,,在取数据时直接过滤掉了) |
#predicate过滤条件
predicate: deptno is not null (type: boolean) |
Statistics: Num rows: 1 Data size: 730 Basic stats: COMPLETE Column stats: NONE |
Select Operator #选取操作
#expressions:需要的字段名称及字段类型
expressions: deptno (type: int), dname (type: string), loc (type: int)
#输出的列名称
outputColumnNames: _col0, _col1, _col2 |
Statistics: Num rows: 1 Data size: 730 Basic stats: COMPLETE Column stats: NONE |
#将小表sink制作成hashmap,在下一个stage的map任务中 Map Join Operator进行连接。
HashTable Sink Operator |
keys: |
0 _col7 (type: int) |
1 _col0 (type: int) |
|
Stage: Stage-3 |
Map Reduce |
Map Operator Tree: |
TableScan |
alias: e |
Statistics: Num rows: 1 Data size: 6610 Basic stats: COMPLETE Column stats: NONE |
Filter Operator #过滤操作
#predicate过滤条件
predicate: deptno is not null (type: boolean) |
Statistics: Num rows: 1 Data size: 6610 Basic stats: COMPLETE Column stats: NONE |
Select Operator |
expressions: empno (type: int), ename (type: string), job (type: string), mgr (type: int), hiredate (type: string), sal (type: double), comm (type: double), deptno (type: int)|
outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, _col6, _col7 |
Statistics: Num rows: 1 Data size: 6610 Basic stats: COMPLETE Column stats: NONE |
Map Join Operator |
condition map: # condition map:join方式 |
Inner Join 0 to 1 |
keys: # keys: join的条件字段 |
0 _col7 (type: int) #第一张表输出的数据集 |
1 _col0 (type: int) #第二张表输出的数据集
#join完成之后输出的字段
outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, _col6, _col7, _col8, _col9, _col10 |
Statistics: Num rows: 1 Data size: 7271 Basic stats: COMPLETE Column stats: NONE |
File Output Operator #文件输出操作 |
compressed: false #是否压缩 |
Statistics: Num rows: 1 Data size: 7271 Basic stats: COMPLETE Column stats: NONE |
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 |
Execution mode: vectorized |
Local Work: |
Map Reduce Local Work |
|
Stage: Stage-0 |
Fetch Operator #客户端获取数据操作 |
limit: -1 #-1表示不限制条数,其它值为限制的条数 |
Processor Tree: |
ListSink |
|
分布式缓存就是:Hadoop为MapReduce框架提供的一种分布式缓存机制,它会将需要缓存的文件分发到各个执行任务的子节点的机器中,各个节点可以自行读取本地文件系统上的数据进行处理。
首先启动一个本地的MR Local Task,会去读小表(根据表的元数据中的统计信息确定),
将小表的数据读入之后生成一个HashTable文件,
将该文件存入hadoop的分布式缓存中;然后启动一个Map任务,
将另外一个表的数据读入之后和上一步存入到入hadoop的分布式缓存中的HashTable文件进行join操作,查出数据。
第二张表一边map一边和缓存做join,不需要shuffle不需要reduce。
这种join是没有shuffle(shuffle:将相同的deptno分到一个reduce上去)进行网络传输的,是性能比较高的join方法。
参考链接:hive的JOIN和SQL执行计划解读
返回顶部
Hive 中对某些情况的查询可以不必使用 MapReduce 计算
。例如:SELECT *
FROM employees;在这种情况下,Hive 可以简单地读取 employee 对应的存储目录下的文件,然后输出查询结果到控制台。hive.fetch.task.conversion
默认是 more,老版本 hive默认是 minimal
,该属性修改为 more 以后,在全局查找、字段查找、limit 查找等都不走mapreduce。none
: disable hive.fetch.task.conversionminimal
: SELECT STAR(*
), 字段查找,FILTER on partition columns, LIMIT onlymore
: SELECT *
,字段查找, FILTER, LIMIT only (support TABLESAMPLE and virtual columns虚拟字段)set hive.fetch.task.conversion;
set hive.fetch.task.conversion=none;
select * from emp;
select ename from emp;
select ename from emp limit 3;
(2)把 hive.fetch.task.conversion 设置成 minimal,然后执行查询语句,如下查询方式都不会执行 mapreduce 程序。
set hive.fetch.task.conversion=minimal;
select * from emp;
select ename from emp;
select ename from emp limit 3;
select * from dept_partition where day='20200402'; --基于分区字段过滤
(2)把 hive.fetch.task.conversion 设置成 more,然后执行查询语句,如下查询方式都不会执行 mapreduce 程序。
set hive.fetch.task.conversion=more;
select * from emp;
select ename from emp;
select ename from emp limit 3;
select ename from emp where sal>2000;
select * from dept_partition where day='20200402'; --基于分区字段过滤,分区字段是虚拟字段
返回顶部
Hive 可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短
。--开启本地模式
set hive.exec.mode.local.auto=true; //开启本地 mr
//设置 local mr 的最大输入数据量,当输入数据量小于这个值时采用 local mr 的方式,默认为 134217728,即 128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
//设置 local mr 的最大输入文件个数,当输入文件个数小于这个值时采用 local mr 的方式,默认为 4
set hive.exec.mode.local.auto.input.files.max=10;
select count(*) from emp group by deptno;
set hive.exec.mode.local.auto=true;
select count(*) from emp group by deptno;
将 key 相对分散,并且数据量小的表放在 join 的左边,可以使用 map join 让小的维度表先进内存。在 map 端完成 join。
实际测试发现:新版的 hive 已经对小表 JOIN 大表和大表 JOIN 小表进行了优化。小表放在左边和右边已经没有区别。
案例实操
set hive.auto.convert.join = true; --默认为 true
set hive.mapjoin.smalltable.filesize = 25000000;
[hyj@hadoop102 datas]$ vim smalltable #10万条小表数据(12.4MB)
95048 20111230000005 57375476989eea12893c0c3811607bcf 奇艺高清 1 1 http:456456www.123qiyi.com456
95096 20111230000005 66c5bb7774e31d0a22278249b26bc83a 凡人修仙传 3 1 http:456456www.123booksky.org456BookDetail.aspx?BookID=1050804&Level=1
95144 20111230000007 b97920521c78de70ac38e3713f524b50 本本联盟 1 1 http:456456www.123bblianmeng.com456
95192 20111230000008 6961d0c97fe93701fc9c0d861d096cd9 华南师范大学图书馆 1 1 http:456456lib.scnu.edu.cn456
95192 20111230000008 f2f5a21c764aebde1e8afcc2871e086f 在线代理 2 1 http:456456proxyie.cn456
95144 20111230000009 96994a0480e7e1edcaef67b20d8816b7 伟大导演 1 1 http:456456movie.douban.com456review4561128960456
95096 20111230000009 698956eb07815439fe5f46e9a4503997 youku 1 1 http:456456www.123youku.com456
95144 20111230000009 599cd26984f72ee68b2b6ebefccf6aed 安徽合肥365房产网 1 1 http:456456hf.house365.com456
95192 20111230000010 f577230df7b6c532837cd16ab731f874 哈萨克网址大全 1 1 http:456456www.123kz321.com456
95192 20111230000010 285f88780dd0659f5fc8acc7cc4949f2 IQ数码 1 1 http:456456www.123iqshuma.com456
[hyj@hadoop102 datas]$ vim bigtable #100万条大表数据(123MB)
0 20111230000005 57375476989eea12893c0c3811607bcf 奇艺高清 1 1 http:456456www.qiyi.com456
0 20111230000005 66c5bb7774e31d0a22278249b26bc83a 凡人修仙传 3 1 http:456456www.booksky.org456BookDetail.aspx?BookID=1050804&Level=1
0 20111230000007 b97920521c78de70ac38e3713f524b50 本本联盟 1 1 http:456456www.bblianmeng.com456
0 20111230000008 6961d0c97fe93701fc9c0d861d096cd9 华南师范大学图书馆 1 1 http:456456lib.scnu.edu.cn456
0 20111230000009 599cd26984f72ee68b2b6ebefccf6aed 安徽合肥365房产网 1 1 http:456456hf.house365.com456
0 20111230000010 f577230df7b6c532837cd16ab731f874 哈萨克网址大全 1 1 http:456456www.kz321.com456
1 20111230000010 285f88780dd0659f5fc8acc7cc4949f2 IQ数码 1 1 http:456456www.iqshuma.com456
1 20111230000011 58e7d0caec23bcb4daa7bbcc4d37f008 张国立的电视剧 2 1 http:456456tv.sogou.com456vertical4562xc3t6wbuk24jnphzlj35zy.html?p=40230600
1 20111230000011 a3b83dc38b2bbc35660dffcab4ed9da8 吹暖花开嘎嘎吧 1 1 http:456456www.7183.info456
1 20111230000011 b89952902d7821db37e8999776b32427 怎么骂一个人不带脏字 1 1 http:456456wenwen.soso.com456z456q131927207.htm
1 20111230000011 7c54c43f3a8a0af0951c26d94a57d6c8 百度一下 你就知道 1 1 http:456456www.baidu.com456
2 20111230000012 1d374b57fbbc81aa0cc38e6f4efb88ec qq老头像 1 1 http:456456tui.qihoo.com45628302631456article_2893190.html
[hyj@hadoop102 datas]$ vim nullid #
\N 20111230000005 57375476989eea12893c0c3811607bcf 奇艺高清 1 1 http:2879www.123qiyi.com/
\N 20111230000005 66c5bb7774e31d0a22278249b26bc83a 凡人修仙传 3 1 http:2879www.123booksky.org/BookDetail.aspx?BookID=1050804&Level=1
\N 20111230000007 b97920521c78de70ac38e3713f524b50 本本联盟 1 1 http:2879www.123bblianmeng.com/
\N 20111230000008 6961d0c97fe93701fc9c0d861d096cd9 华南师范大学图书馆 1 1 http:2879lib.scnu.edu.cn/
\N 20111230000008 f2f5a21c764aebde1e8afcc2871e086f 在线代理 2 1 http:2879proxyie.cn/
\N 20111230000009 96994a0480e7e1edcaef67b20d8816b7 伟大导演 1 1 http:2879movie.douban.com/review/1128960/
\N 20111230000009 698956eb07815439fe5f46e9a4503997 youku 1 1 http:2879www.123youku.com/
\N 20111230000009 599cd26984f72ee68b2b6ebefccf6aed 安徽合肥365房产网 1 1 http:2879hf.house365.com/
\N 20111230000010 f577230df7b6c532837cd16ab731f874 哈萨克网址大全 1 1 http:2879www.123kz321.com/
\N 20111230000010 285f88780dd0659f5fc8acc7cc4949f2 IQ数码 1 1 http:2879www.123iqshuma.com/
\N 20111230000010 f4ba3f337efb1cc469fcd0b34feff9fb 推荐待机时间长的手机 1 1 http:2879mobile.zol.com.cn/148/1487938.html
\N 20111230000010 3d1acc7235374d531de1ca885df5e711 满江红 1 1 http:2879baike.baidu.com/view/6500.htm
\N 20111230000010 dbce4101683913365648eba6a85b6273 光标下载 1 1 http:2879zhidao.baidu.com/question/38626533
//创建大表
create table bigtable(id bigint, t bigint, uid string, keyword string,
url_rank int, click_num int, click_url string) row format delimited
fields terminated by '\t';
// 创建小表
create table smalltable(id bigint, t bigint, uid string, keyword string,
url_rank int, click_num int, click_url string) row format delimited
fields terminated by '\t';
// 创建 join 后的表
create table jointable(id bigint, t bigint, uid string, keyword string,
url_rank int, click_num int, click_url string) row format delimited
fields terminated by '\t';
load data local inpath '/opt/module/data/bigtable' into table bigtable;
load data local inpath '/opt/module/data/smalltable' into table smalltable;
insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from smalltable s
join bigtable b
on b.id = s.id;
insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable b
join smalltable s
on s.id = b.id;
返回顶部
有时 join 超时是因为某些 key 对应的数据太多,而相同 key 对应的数据都会发送到相同的 reducer 上,从而导致内存不够。此时我们应该仔细分析这些异常的 key,很多情况下,这些 key 对应的数据是异常数据,我们需要在 SQL 语句中进行过滤。例如 key 对应的字段为空,操作如下:
<!-- 历史服务器端地址 -->
<property>
<name>mapreduce.jobhistory.address</name>
<value>hadoop102:10020</value>
</property>
<!-- 历史服务器web端地址 -->
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>hadoop102:19888</value>
</property>
(2)启动历史服务器
sbin/mr-jobhistory-daemon.sh start historyserver
(3)查看 jobhistory
http://hadoop102:19888/jobhistory
-- 创建空 id 表
create table nullidtable(id bigint, t bigint, uid string, keyword string,
url_rank int, click_num int, click_url string) row format delimited
fields terminated by '\t';
load data local inpath '/opt/module/hive-3.1.2/datas/nullid' into table nullidtable;
insert overwrite table jointable
select n.* from
nullidtable n left join bigtable o on n.id = o.id;
Time taken: 72.529 seconds
insert overwrite table jointable
select n.* from
(select * from nullidtable where id is not null) n left join bigtable o on n.id = o.id;
Time taken: 47.679 seconds
返回顶部
有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 reducer 上
。例如:
set mapreduce.job.reduces = 5;
(2)JOIN 两张表
insert overwrite table jointable
select n.* from nullidtable n left join bigtable b on n.id = b.id;
结果:如下图所示,可以看出来,出现了数据倾斜,某些 reducer 的资源消耗远大于其他 reducer。
set mapreduce.job.reduces = 5;
(2)JOIN 两张表
insert overwrite table jointable
select n.* from nullidtable n full join bigtable o on
nvl(n.id,rand()) = o.id;
结果:如下图所示,可以看出来,消除了数据倾斜,负载均衡 reducer 的资源消耗
返回顶部
hive.auto.convert.join=true
-- 2.0版本之前的控制属性
hive.mapjoin.smalltable.filesize=25M
-- 2.0版本开始由以下参数控制
--Hive是否支持根据输入文件大小进行普通join到mapjoin的转换优化。如果开启此参数,并且n-1个表/分区的大小之和小于指定大小后,join直接转换为mapjoin。
set hive.auto.convert.join.noconditionaltask = true;
-- n-way join的n-1个表/分区的大小之和小于这个大小,join直接转换为mapjoin
set hive.auto.convert.join.noconditionaltask.size = 10000000;
(1)创建第二张大表
create table bigtable2(
id bigint,
t bigint,
uid string,
keyword string,
url_rank int,
click_num int,
click_url string)
row format delimited fields terminated by '\t';
load data local inpath '/opt/module/hive-3.1.2/datas/bigtable' into table bigtable2;
测试大表直接 JOIN
insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable s
join bigtable2 b
on b.id = s.id;
Time taken: 69.475 seconds
(2)创建分通表 1,桶的个数不要超过可用 CPU 的核数
create table bigtable_buck1(
id bigint,
t bigint,
uid string,
keyword string,
url_rank int,
click_num int,
click_url string)
clustered by(id)
sorted by(id)
into 6 buckets
row format delimited fields terminated by '\t';
load data local inpath '/opt/module/hive-3.1.2/datas/bigtable' into table bigtable_buck1;
(3)创建分通表 2,桶的个数不要超过可用 CPU 的核数
create table bigtable_buck2(
id bigint,
t bigint,
uid string,
keyword string,
url_rank int,
click_num int,
click_url string)
clustered by(id)
sorted by(id)
into 6 buckets
row format delimited fields terminated by '\t';
load data local inpath '/opt/module/hive-3.1.2/datas/bigtable' into table bigtable_buck2;
-- 开启分桶join
set hive.optimize.bucketmapjoin = true;
(3)要求:分桶字段 = Join字段 ,桶的个数相等或者成倍数
(4)测试
insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable_buck1 s
join bigtable_buck2 b
on b.id = s.id;
-- 开启分桶SMB join
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.auto.convert.sortmerge.join=true; --Will the join be automatically converted to a sort-merge join, if the joined tables pass the criteria for sort-merge join.
(3)要求:分桶字段 = Join字段 = 排序字段 ,桶的个数相等或者成倍数
(4)测试
insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable_buck1 s
join bigtable_buck2 b
on b.id = s.id;
返回顶部
默认情况下,Map 阶段同一 Key 数据分发给同一个 reduce,当一个 key 数据过大时就倾斜了.
并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在 Map 端进行部分聚合,最后在 Reduce 端得出最终结果。
set hive.map.aggr = true
set hive.groupby.mapaggr.checkinterval = 100000
set hive.groupby.skewindata = true
当选项设定为 true,生成的查询计划会有两个 MR Job
。第一个 MR Job 中,Map 的输出结果会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中
,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
select deptno from emp group by deptno;
优化以后
set hive.groupby.skewindata = true;
select deptno from emp group by deptno;
返回顶部
数据量小的时候无所谓,数据量大的情况下,由于 COUNT DISTINCT 操作需要用一个Reduce Task 来完成,这一个 Reduce 需要处理的数据量太大,就会导致整个 Job 很难完成,一般 COUNT DISTINCT 使用先 GROUP BY 再 COUNT 的方式替换,但是需要注意 group by 造成的数据倾斜问题.
set mapreduce.job.reduces = 5;
(2)执行去重 id 查询
select count(distinct id) from bigtable;
(3)采用 GROUP by 去重 id
select count(id) from (select id from bigtable group by id) a;
虽然会多用一个 Job 来完成,但在数据量大的情况下,这个绝对是值得的。
尽量避免笛卡尔积,join 的时候不加 on 条件,或者无效的 on 条件,Hive 只能使用 1 个reducer 来完成笛卡尔积。
列处理:在 SELECT 中,只拿需要的列,如果有分区,尽量使用分区过滤,少用 SELECT *。
行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在 Where 后面,那么就会先全表关联,之后再过滤,比如:
案例实操:
select o.id from bigtable b join bigtable o on o.id = b.id where o.id <= 10;
Time taken: 22.953 seconds, Fetched: 1081 row(s)
select b.id from bigtable b join (select id from bigtable where id <= 10) o on b.id = o.id;
Time taken: 21.575 seconds, Fetched: 1081 row(s)
返回顶部
input 的文件总个数,input 的文件大小,集群设置的文件块大小
。针对上面的问题 2 和 3,我们需要采取两种方式来解决:即减少 map 数和增加 map 数;
当 input 的文件都很大,任务逻辑复杂,map 执行非常慢的时候,可以考虑增加 Map 数,来使得每个 map 处理的数据量减少,从而提高任务的执行效率。增加 map 的方法为:根据
computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M
公式,
调整 maxSize 最大值。让 maxSize 最大值低于 blocksize 就可以增加 map 的个数。
案例实操:
hive (default)> select count(*) from emp;
Hadoop job information for Stage-1: number of mappers: 1; number of
reducers: 1
hive (default)> set mapreduce.input.fileinputformat.split.maxsize=100;
hive (default)> select count(*) from emp;
Hadoop job information for Stage-1: number of mappers: 6; number of
reducers: 1
返回顶部
set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
-- 如果hive的程序,只有maptask,将MapTask产生的所有小文件进行合并
set hive.merge.mapfiles = true;
-- 如果hive的程序,有Map和ReduceTask,将ReduceTask产生的所有小文件进行合并
set hive.merge.mapredfiles = true;
-- 每一个合并的文件的大小
set hive.merge.size.per.task = 268435456;
--平均每个文件的大小,如果小于这个值就会进行合并
set hive.merge.smallfiles.avgsize = 16777216;
返回顶部
hive.exec.reducers.bytes.per.reducer=256000000
hive.exec.reducers.max=1009
N=min(参数 2,总输入数据量/参数 1)
set mapreduce.job.reduces = 15;
Hive 会将一个查询转化成一个或者多个阶段。这样的阶段可以是 MapReduce 阶段、抽样阶段、合并阶段、limit 阶段。或者 Hive 执行过程中可能需要的其他阶段。默认情况下,Hive 一次只会执行一个阶段。不过,某个特定的 job 可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个 job 的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么 job 可能就越快完成。
通过设置参数 hive.exec.parallel 值为 true,就可以开启并行执行。不过,在共享集群中,需要注意下,如果 job 中并行阶段增多,那么集群利用率就会增加。
set hive.exec.parallel=true; //打开任务并行执行
set hive.exec.parallel.thread.number=16; //同一个 sql 允许最大并行度,默认为8。
--线程数越多,程序运行速度越快,但同样更消耗CPU资源
当然,得是在系统资源比较空闲的时候才有优势,否则,没资源,并行也起不来。
返回顶部
Hive 可以通过设置防止一些危险操作:
hive.strict.checks.no.partition.filter
设置为 true 时,对于分区表,除非 where 语句中含有分区字段过滤条件来限制范围,否则不允许执行
。换句话说,就是用户不允许扫描所有分区
。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。hive.strict.checks.orderby.no.limit
设置为 true 时,对于使用了 order by 语句的查询,要求必须使用 limit 语句
。因为 order by 为了执行排序过程会将所有的结果数据分发到同一个Reducer 中进行处理,强制要求用户增加这个 LIMIT 语句可以防止 Reducer 额外执行很长一段时间(开启了 limit 可以在数据进入到 reduce 之前就减少一部分数据)。hive.strict.checks.cartesian.product
设置为 true 时,会限制笛卡尔积的查询
。对关系型数据库非常了解的用户可能期望在 执行 JOIN 查询的时候不使用 ON 语句而是使用 where 语句,这样关系数据库的执行优化器就可以高效地将 WHERE 语句转化成那个 ON 语句。不幸的是,Hive 并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。hive.execution.engine
参数属性控制。支持DAG作业
的开源计算框架,它可以将多个有依赖的作业转换为一个作业从而大幅提升DAG作业的性能
。核心思想是将Map和Reduce两个操作进一步拆分,即Map被拆分成Input、Processor、Sort、Merge和Output, Reduce被拆分成Input、Shuffle、Sort、Merge、Processor和Output等,这样,这些分解后的元操作可以任意灵活组合,产生新的操作,这些操作经过一些控制程序组装后,可形成一个大的DAG作业。最终Tez也会将程序提交给YARN来实现运行
。[hyj@hadoop102 module]$ mkdir tez
[hyj@hadoop102 module]$ tar -zxvf /opt/software/tez-0.10.1-SNAPSHOT-minimal.tar.gz -C ./tez/
[hyj@hadoop102 software]$ hadoop fs -mkdir /tez
[hyj@hadoop102 software]$ hadoop fs -put ./tez-0.10.1-SNAPSHOT.tar.gz /tez
[hyj@hadoop102 software]$ vim $HADOOP_HOME/etc/hadoop/tez-site.xml
添加如下内容:
<configuration>
<property>
<name>tez.lib.urisname>
<value>${fs.defaultFS}/tez/tez-0.10.1-SNAPSHOT.tar.gzvalue>
property>
<property>
<name>tez.use.cluster.hadoop-libsname>
<value>truevalue>
property>
<property>
<name>tez.am.resource.memory.mbname>
<value>1024value>
property>
<property>
<name>tez.am.resource.cpu.vcoresname>
<value>1value>
property>
<property>
<name>tez.container.max.java.heap.fractionname>
<value>0.4value>
property>
<property>
<name>tez.task.resource.memory.mbname>
<value>1024value>
property>
<property>
<name>tez.task.resource.cpu.vcoresname>
<value>1value>
property>
configuration>
将tez-site.xml分发给其它Hadoop节点
[hyj@hadoop102 software]$ cd /opt/module/hadoop-3.1.3/etc/hadoop/shellprofile.d/
[hyj@hadoop102 shellprofile.d]$ ls
example.sh
[hyj@hadoop102 shellprofile.d]$ vim tez.sh
添加如下内容:
hadoop_add_profile tez
function _tez_hadoop_classpath
{
hadoop_add_classpath "$HADOOP_HOME/etc/hadoop" after
hadoop_add_classpath "/opt/module/tez/*" after
hadoop_add_classpath "/opt/module/tez/lib/*" after
}
[hyj@hadoop102 module]$ vim $HIVE_HOME/conf/hive-site.xml
添加如下内容:
<property>
<name>hive.execution.enginename>
<value>tezvalue>
property>
<property>
<name>hive.tez.container.sizename>
<value>1024value>
property>
[hyj@hadoop102 module]$ rm -fr /opt/module/tez/lib/slf4j-log4j12-1.7.10.jar
返回顶部
在使用ORC文件时,为了加快读取ORC文件中的数据内容,ORC提供了两种索引机制:Row Group Index
和 Bloom Filter Index
可以帮助提高查询ORC文件的性能,当用户写入数据时,可以指定构建索引,当用户查询数据时,可以根据索引提前对数据进行过滤,避免不必要的数据扫描。
当查询中有<,>,=的操作时,会根据min/max值,跳过扫描不包含的stripes
。而其中为每个stripe建立的包含min/max值的索引,就称为Row Group Index行组索引
,也叫min-max Index大小对比索引,或者Storage Index。orc.create.index=true
之后,便会建立Row Group Index,需要注意的是,为了使Row Group Index有效利用,向表中加载数据时,必须对需要使用索引的字段进行排序
,否则,min/max会失去意义。另外,这种索引主要用于数值型字段的范围查询过滤优化上。set hive.optimize.index.filter=true;
永久生效,请配置在hive-site.xml中
create table smalltable_orc_index
stored as orc tblproperties("orc.create.index"="true")
as select * from smalltable
distribute by id
sort by id;
select count(*) from smalltable_orc_index where id > 95100;
”orc.bloom.filter.columns”=”columnName……”
来指定为哪些字段建立BloomFilter索引,这样,在生成数据的时候,会在每个stripe中,为该字段建立BloomFilter的数据结构,当查询条件中包含对该字段的=号过滤时候
,先从BloomFilter中获取以下是否包含该值,如果不包含,则跳过该stripe。create table smalltable_orc_bloom
stored as orc tblproperties("orc.create.index"="true","orc.bloom.filter.columns"="id,url_rank")
as select * from smalltable
distribute by id
sort by id;
select
count(*)
from smalltable_orc_bloom
where id > 95100
and url_rank = '3' ;
返回顶部
Hive的默认查询执行引擎一次处理一行,而矢量化查询执行是一种Hive针对ORC文件操作的特性,目的是按照每批1024行读取数据,并且一次性对整个记录整合(而不是对单条记录)应用操作,提升了像过滤, 联合, 聚合等等操作的性能。
注意:要使用矢量化查询执行,就必须以ORC格式存储数据。
set hive.vectorized.execution.enabled = true;
set hive.vectorized.execution.reduce.enabled = true;
Hadoop默认会为每个Task启动一个JVM来运行
,那么就会启动100个JVM来运行MapTask,在JVM启动时内存开销大,尤其是Job大数据量情况,如果单个Task数据量比较小,也会申请JVM资源,这就导致了资源紧张及浪费的情况。-- Hadoop3之前的配置,在mapred-site.xml中添加以下参数
-- Hadoop3中已不再支持该选项
mapreduce.job.jvm.numtasks=10
返回顶部
如果你碰到一堆 SQL,并且这一堆 SQL 的模式还一样。都是从同一个表进行扫描,做不同的逻辑。有可优化的地方:如果有 n 条 SQL,每个 SQL 执行都会扫描一次这张表。
insert .... select id,name,sex, age from student where age > 17;
insert .... select id,name,sex, age from student where age > 18;
insert .... select id,name,sex, age from student where age > 19;
隐藏了一个问题:这种类型的 SQL 有多少个,那么最终。这张表就被全表扫描了多少次
insert into t_ptn partition(city=A). select id,name,sex, age from student
where city= A;
insert into t_ptn partition(city=B). select id,name,sex, age from student
where city= B;
insert into t_ptn partition(city=c). select id,name,sex, age from student
where city= c;
修改为:
from student
insert into t_ptn partition(city=A) select id,name,sex, age where city= A
insert into t_ptn partition(city=B) select id,name,sex, age where city= B
如果一个 HQL 底层要执行 10 个 Job,那么能优化成 8 个一般来说,肯定能有所提高,多重插入就是一个非常实用的技能。一次读取,多次插入
,有些场景是从一张表读取数据后,要多次利用。
在 Hive 的早期版本中,in/exists 语法是不被支持的,但是从 hive-0.8x 以后就开始支持这个语法。但是不推荐使用这个语法。虽然经过测验,Hive-2.3.6 也支持 in/exists 操作,但还是推荐使用 Hive 的一个高效替代方案:left semi join
比如说:-- in / exists 实现
select a.id, a.name from a where a.id in (select b.id from b);
select a.id, a.name from a where exists (select id from b where a.id = b.id);
可以使用 join 来改写:
select a.id, a.name from a join b on a.id = b.id;
应该转换成:
– left semi join 实现
select a.id, a.name from a left semi join b on a.id = b.id;
默认的优化器引擎RBO
,会选择先从索引中查询id = 100的值所在的位置,再根据索引记录位置去读取对应的数据,但是这并不是最佳的执行方案。有id=100的值有900条,占了总数据的90%,这时候是没有必要检索索引以后再检索数据的,可以直接检索数据返回,这样的效率会更高,更节省资源,这种方式就是CBO优化器引擎
会选择的方案。很明显CBO引擎更加智能,所以在使用Hive时,我们可以配置底层的优化器引擎为CBO引擎。
set hive.cbo.enable=true;
set hive.compute.query.using.stats=true;
set hive.stats.fetch.column.stats=true;
set hive.stats.fetch.partition.stats=true;
返回顶部
-- 构建分区信息元数据
ANALYZE TABLE tablename
[PARTITION(partcol1[=val1], partcol2[=val2], ...)]
COMPUTE STATISTICS [noscan];
-- 构建列的元数据
ANALYZE TABLE tablename
[PARTITION(partcol1[=val1], partcol2[=val2], ...)]
COMPUTE STATISTICS FOR COLUMNS ( columns name1, columns name2...) [noscan];
-- 查看元数据
DESC FORMATTED [tablename] [columnname];
ANALYZE TABLE tb_login_part PARTITION(logindate) COMPUTE STATISTICS;
ANALYZE TABLE tb_login_part COMPUTE STATISTICS FOR COLUMNS userid;
desc formatted tb_login_part userid;
谓词下推 Predicate Pushdown(PPD)的思想简单点说就是在不影响最终结果的情况下,尽量将过滤条件提前执行
。谓词下推后,过滤条件在map端执行,减少了map端的输出,降低了数据在集群上传输的量,降低了Reduce端的数据负载,节约了集群的资源,也提升了任务的性能。
-- 默认自动开启谓词下推
hive.optimize.ppd=true;
返回顶部
绝大部分任务
都很快完成,只有一个或者少数几个任务执行的很慢
甚至最终执行失败,这样的现象为数据倾斜现象。按照 Key 分组以后,少量的任务负责绝大部分数据的计算
,也就是说产生数据倾斜的 HQL 中一定存在分组操作,那么从 HQL 的角度,我们可以将数据倾斜分为单表携带了 GroupBy 字段的查询
和两表(或者多表)Join 的查询
。当任务中存在 GroupBy 操作同时聚合函数为 count 或者 sum 可以设置参数来处理数据倾斜问题
--是否在 Map 端进行聚合,默认为 True
set hive.map.aggr = true; --通过减少Reduce的输入量,避免每个Task数据差异过大导致数据倾斜
--在 Map 端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000;
有数据倾斜的时候进行负载均衡(默认是 false),当选项设定为 true,生成的查询计划会有两个 MR Job。
set hive.groupby.skewindata = true;
-- 开启随机分区,走两个MapReduce
hive.groupby.skewindata=true;
返回顶部
set hive.exec.reducers.bytes.per.reducer = 256000000
set hive.exec.reducers.max = 1009
N=min(参数 2,总输入数据量/参数 1)(参数 2 指的是上面的 1009,参数 1 值得是 256M)
set mapreduce.job.reduces = 15;
返回顶部
实际业务需求中往往需要构建两张表的Join实现,如果两张表比较大,无法实现Map Join,只能走Reduce Join,那么当关联字段中某一种值过多的时候依旧会导致数据倾斜的问题,面对Join产生的数据倾斜,我们核心的思想是尽量避免Reduce Join的产生,优先使用Map Join来实现,但往往很多的Join场景不满足Map Join的需求,那么我们可以以下几种方案来解决Join产生的数据倾斜问题:
需求:两张表关联得到今天每个订单的用户信息
实现1:直接关联,实现大表Join大表
select a.*,b.* from A join B on a.userid = b.userid;
由于两张表比较大,无法走Map Join,只能走Reduce Join,容易产生数据倾斜。
实现2:将下了订单的用户的数据过滤出来,再Join
select a.*,d.*
from (
select a.*,d.*
from (
-- 获取所有下订单的用户信息
select
b.*
from
-- 获取所有下订单的userid
( select distinct a.userid from A a ) c join B b on c.userid = b.userid ) d
join
A a on d.userid = a.userid;
通过多次Map Join来代替Reduce Join,性能更好也可以避免数据倾斜
返回顶部
在编写 Join 查询语句时,如果确定是由于 join 出现的数据倾斜,那么请做如下设置:
# join 的键对应的记录条数超过这个值则会进行分拆,值根据具体数据量设置
set hive.skewjoin.key=100000;
# 如果是 join 过程出现倾斜应该设置为 true
set hive.optimize.skewjoin=false;
如果开启了,在 Join 过程中 Hive 会将计数超过阈值 hive.skewjoin.key(默认 100000)的倾斜 key 对应的行临时写进文件中,然后再启动另一个 job 做 map join 生成结果。
通过hive.skewjoin.mapjoin.map.tasks 参数还可以控制第二个 job 的 mapper 数量,默认 10000。
set hive.skewjoin.mapjoin.map.tasks=10000;
详情看上面↑Bucket Join and SMB(Sort Merge Bucket join)
返回顶部
以单台服务器 128G 内存,32 线程为例。
yarn.nodemanager.resource.cpu-vcores 参数设为 28,也就是 YARN 能够利用其中的 28 核
,此时将 spark.executor.cores 设为 4 最合适,最多可以正好分配给 7 个 Executor 而不造成浪费。又假设 yarn.nodemanager.resource.cpuvcores 为 26,那么将 spark.executor.cores 设为 5 最合适,只会剩余 1 个核。每个 Executor 可利用的堆内内存量和堆外内存量
。堆内内存越大,Executor 就能缓存更多的数据,在做诸如 map join 之类的操作时就会更快,但同时也会使得GC 变得更麻烦。spark.yarn.executor.memoryOverhead 的默认值是 executorMemory * 0.10,最小值为 384M(每个 Executor)set spark.executor.memory=11.2g;
set spark.yarn.executor.memoryOverhead=2.8g;
同理,这两个内存参数相加的总量也不能超过单个 Container 最多能申请到的内存量, 即 yarn.scheduler.maximum-allocation-mb
配置的值。
该参数表示执行查询时一共启动多少个 Executor 实例
,这取决于每个节点的资源分配情况以及集群的节点数。若我们一共有 10 台 32C/128G 的节点,并按照上述配置(即每个节点承载 7 个 Executor),那么理论上讲我们可以将 spark.executor.instances 设为 70,以使集群资源最大化利用。但是实际上一般都会适当设小一些(推荐是理论值的一半左右,比如 40),因为 Driver 也要占用资源,并且一个 YARN 集群往往还要承载除了 Hive on Spark 之外的其他业务。
上面所说的固定分配 Executor 数量的方式可能不太灵活,尤其是在 Hive 集群面向很多用户提供分析服务的情况下。所以更推荐将 spark.dynamicAllocation.enabled 参数设为 true,以启用 Executor 动态分配
。
set hive.execution.engine=spark;
set spark.executor.memory=11.2g;
set spark.yarn.executor.memoryOverhead=2.8g;
set spark.executor.cores=4;
set spark.executor.instances=40;
set spark.dynamicAllocation.enabled=true;
set spark.serializer=org.apache.spark.serializer.KryoSerializer;
该参数表示每个 Driver 可利用的 CPU 核心数
。绝大多数情况下设为 1 都够用。
这两个参数分别表示每个 Driver 可利用的堆内内存量和堆外内存量
。根据资源富余程度和作业的大小,一般是将总量控制在 512MB~4GB 之间,并且沿用 Executor 内存的“二八分配方式”。例如,spark.driver.memory 可以设为约 819MB,spark.driver.memoryOverhead 设为约 205MB,加起来正好 1G。
返回顶部