黑洞

这里藏着一些独特的想法

0%

Hive的优化大杂烩

鬼记得住,备查。

Fetch 抓取机制

  • 功能:在执行sql的时候,能不走MapReduce程序处理就尽量不走MapReduce程序处理。

  • 尽量直接去操作数据文件。

  • 设置:set hive.fetch.task.conversion = more

1
2
3
4
5
6
7
8
--在下述3种情况下 sql不走mr程序

--全局查找
select * from student;
--字段查找
select num,name from student;
--limit 查找
select num,name from student limit 2;

MapReduce 本地模式

  • 功能:如果非要执行MapReduce程序,能够本地执行的,尽量不提交yarn上执行。

  • 默认是关闭的,意味着只要走MapReduce就提交yarn执行。

1
2
set mapreduce.framework.name = local 本地模式
set mapreduce.framework.name = yarn 集群模式
  • Hive提供了一个参数,自动切换MapReduce程序为本地模式,如果不满足条件,就执行yarn模式。
1
2
3
4
5
6
7
8
9
10
11
12
set hive.exec.mode.local.auto = true;

--3个条件必须都满足 自动切换本地模式

--数据量小于128M
The total input size of the job is lower than: hive.exec.mode.local.auto.inputbytes.max (128MB by default)

--maptask个数少于4个
The total number of map-tasks is less than: hive.exec.mode.local.auto.tasks.max (4 by default)

--reducetask个数是0 或者 1
The total number of reduce tasks required is 1 or 0.
  • 切换Hive的执行引擎,改用Spark。

join 优化

空值转换

两个大表join后的数据量是非常巨大的,如果其中有NULL值,并且对应的行数据不重要时,尽可能地提前过滤。

1
SELECT a.* FROM (SELECT * FROM nullidtable WHERE id IS NOT NULL ) a JOIN ori b ON a.id =b.id;

如果需要保留行数据,那就要转换NULL值,并且加入随机字符,避免数据倾斜。

1
2
CASE WHEN a.id IS NULL THEN 'xxx任意字符串' ELSE a.id END
CASE WHEN a.id IS NULL THEN concat('hive', rand()) ELSE a.id

大表 join 小表

map join

Hive自动尝试选择map端join,提高join的效率,省去shuffle的过程。

开启 mapjoin 参数设置:

1
2
3
4
-- (1)设置自动选择 mapjoin
set hive.auto.convert.join = true; --默认为 true
-- (2)小表的阈值设置:
set hive.mapjoin.smalltable.filesize= 25000000;

bucket map join

使用桶表join必须同时满足以下几个条件:

  1. set hive.optimize.bucketmapjoin = true; 默认为true
  2. 一个表的bucket数是另一个表bucket数的整数倍(小表的bucket数设置为大表的倍数)
  3. bucket列join列是同一列
  4. 必须是应用在map join的场景中

如果不是桶表,只会进行普通join。

大表 join 大表

SMB(Sort-Merge-Bucket) join

大表对小表应该使用MapJoin来进行优化,但是如果是大表对大表进行shuffle,那就非常可怕,第一个慢不用说,第二个容易出异常,此时就可以使用SMB Join来提高性能。SMB Join基于bucket-mapjoin的有序bucket,可实现在map端完成join操作,可以有效地减少或避免shuffle的数据量。SMB join的条件和Map join类似但又不同。

开启一堆参数:

1
2
3
4
5
6
7
8
9
10
--开启bucketmapjoin
set hive.optimize.bucketmapjoin = true;
--开启SMB Join
set hive.auto.convert.sortmerge.join=true;
set hive.auto.convert.sortmerge.join.noconditionaltask=true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
--写入数据强制分桶
set hive.enforce.bucketing=true;
--写入数据强制排序
set hive.enforce.sorting=true;

要求:

  1. 两表bucket数相等
  2. Bucket列Join列Sort列是同一列
  3. 必须是应用在bucket mapjoin的场景中

Hive并不检查两个join的表是否已经做好bucket且sorted,需要用户自己去保证join的表数据sorted,否则可能数据不正确。

有两个办法:

  1. hive.enforce.sorting设置为true。开启强制排序时,插数据到表中会进行强制排序,默认false
  2. 插入数据时用distribute c1 sort by c1或者cluster by c1

另外,表创建时必须是排序的分桶表。

1
2
3
4
5
6
7
8
9
CREATE TABLE t_usa_covid19_bucket(
count_date string,
county string,
state string,
fips int,
cases int,
deaths int)
CLUSTERED BY(state)
sorted by (cases desc) INTO 5 BUCKETS;

调整 MR task 个数

maptask 个数

如果是在MapReduce中,maptask是通过逻辑切片机制决定的。

在Hive中,影响的因素很多。比如逻辑切片机制,文件是否压缩、压缩之后是否支持切割。因此在Hive中,想要调整MapTask的个数,直接去HDFS调整文件的大小和个数,效率较高

如果小文件多,就进行小文件的合并,合并的大小最好等于block size。
如果大文件多,就调整block size。

1
2
3
4
5
6
7
8
9
10
11
12
-- 是否开启map端小文件合并(map-only)
hive.merge.mapfiles

-- 是否开启reduce端小文件合并操作
hive.merge.mapredfiles

-- 合并后输出文件的最大值
hive.merge.size.per.task

-- 判断输出文件的平均大小
-- 当这个小于设置值时 认为出现了小文件问题 需要进行合并操作
hive.merge.smallfiles.avgsize

reducetask 个数

在Hive中,reducetask个数受以下几个条件控制:

1
2
3
4
5
6
7
8
9
10
11
-- 每个 Reduce 处理的数据量默认是 256MB
hive.exec.reducers.bytes.per.reducer=256000000

-- 每个任务最大的 reduce 数,默认为 1009
hive.exec.reducsers.max=1009

-- 该值默认为-1,由 hive 自己根据任务情况进行判断,一旦设置前两个参数就不生效了。
-- 如果用户用户不设置 hive将会根据数据量或者sql需求自己评估reducetask个数。
-- 用户设置的不一定生效,如果用户设置的和sql执行逻辑有冲突。
-- 比如order by,在sql编译期间,hive又会将reducetask设置为合理的个数。
mapreduce.job.reduces = -1

并行优化

并行编译

Hive在同一时刻只能编译一个会话中的SQL。如果有多个会话一起来执行SQL, 就会出现排队的情况。只有当这一个会话中SQL全部编译后,才能编译另一个会话的SQL,执行效率很慢。

1
2
3
4
5
-- 是否开启并行编译 设置为true
hive.driver.parallel.compilation

-- 最大允许同时有多少个SQL一起编译 设置为0表示无限制
hive.driver.parallel.compilation.global.limit

说明:这两项可以建议直接在CM的hive配置窗口上进行永久配置。

并行执行

  • 如果hive sql底层的某些stage阶段可以并行执行,就可以提高执行效率,前提是stage之间没有依赖。

  • 弊端:服务器瞬时压力变大。

1
2
3
4
5
--是否并行执行作业。适用于可以并行运行的 MapReduce 作业,例如在多次插入期间移动文件以插入目标。
set hive.exec.parallel=true;

--最多可以并行执行多少个作业。默认为8。
set hive.exec.parallel.thread.number=16;

严格模式

注意:不要和动态分区的严格模式搞混淆。

1
set hive.mapred.mode = strict --默认是严格模式  nonstrict

开启之后hive会禁止一些用户都意想不到的错误,包括效率低下的操作。不允许运行一些有风险的查询。

例如:

  1. 如果是分区表,没有where进行分区裁剪,禁止执行!
  2. order by语句后必须加limit

矢量化查询

Hive的默认查询执行引擎一次处理一行,而矢量化查询是一种hive特性,目的是按照每批1024行读取数据,并且一次性对整个记录整合(而不是对单条记录)应用操作。

注意:要使用矢量化查询,就必须以ORC格式存储数据。

1
set hive.vectorized.execution.enabled=true;

读取零拷贝

在Hive读取数据的时候,只需要读取跟SQL相关的列数据即可,不使用的列不进行读取,从而减少读取的数据量,提升效率。

1
set hive.exec.orc.zerocopy=true;

注意:要使用读取零拷贝,就必须以ORC格式存储数据。

关联优化器

在Hive的一些复杂关联查询中,可能同时还包含有group by等能够触发shuffle的操作,有些时候shuffle操作是可以共享的。设置关联优化器选项,可以尽量减少复杂查询中的shuffle,从而提升性能。

1
set hive.optimize.correlation=true;
如果觉得文章写得不错或对您有帮助,请我喝杯柠檬茶吧!