[hive] hive tuning experience

1. Hive optimizes itself

Optimized for commands like union

2. Data localization rate

HDFS data localization rate affects hive performance

In the case of a certain data size, 500 128M files and 2 30G files run hive tasks, and the performance is different. The biggest difference between the two is that the latter needs to be transmitted across the network when reading files, while The former is local read and write. Data localization rate issues.

image.png

3. Data format

hive provides text, sequenceFile, RCFile, ORC, Parquest and other formats.

  • sequenceFile is a flat file with a binary key/value pair structure, which is widely used in MapReduce.
  • Parquet is a columnar storage format compatible with multiple data engines, MapReduce and Spark.
  • An optimization of RCFile in ORC, one of the mainstream choices.

4. Partitioning and bucketing

1. Partition table:

Summary: The meaning of the partition table is actually very simple to understand. It is to create a folder on the system and put the classified data under different folders to speed up the query speed.

Understand that partitions are folders divided and conquered. When querying, they can be used as column names to display the scope of the query.

  • Key point 1: partitioned by (dt String, country string); When creating the table, specify that this is a partitioned table. A two-level directory will be created, the first directory name and the second level directory name rules

The columns defined in the PARTITIONED BY clause are formal columns in the table and become partition columns. But there are no such values ​​in the data file, it just represents the directory.

  • Key point 2: partition (dt='2001-01-01',country='GB'); When uploading data, upload the data to different partitions respectively. That is, they are placed in different subdirectories.

2. Dynamic partition table: 

关闭严格分区模式
动态分区模式时是严格模式,也就是至少有一个静态分区。
set hive.exec.dynamic.partition.mode=nonstrict    //分区模式,默认nostrict
set hive.exec.dynamic.partition=true            //开启动态分区,默认true
set hive.exec.max.dynamic.partitions=1000        //最大动态分区数,默认1000
复制代码

Why use dynamic partitioning? Let's take an example. If China has 50 provinces, each province has 50 cities, and each city has 100 districts, how long will it take us to use static partitions to finish. All we want to use dynamic partitioning.

动态分区默认是没有开启。开启后默认是以严格模式执行的,在这种模式下需要至少一个分区字段是静态的。 这有助于阻止因设计错误导致导致查询差生大量的分区。列如:用户可能错误使用时间戳作为分区表字段。然后导致每秒都对应一个分区!这样我们也可以采用相应的措施:

3. 分桶表:

每一个表或者分区,Hive可以进一步组织成桶。也就是说,桶为细粒度的数据范围划分。

分桶规则:对分桶字段值进行哈希,哈希值除以桶的个数求余,余数决定了该条记录在哪个桶中,也就是余数相同的在一个桶中。分桶不会改变原有表和原有分区目录的组织方式。只是更改了数据在文件中的分布。

优点:1、提高join查询效率 2、提高抽样效率

可以用 desc formatted [表名] 来查看目录组织方式
复制代码

五、 干预sql的运行方式

  • 改写sql,实现对计算引擎执行过程的调优
  • 通过sql-hint语法,实现对计算引擎执行过程的干预
  • 通过数据库开放的一些配置,实现对计算引擎的干预

  具体如下:

1. 使用grouping sets grouping__id rollup cube等代替group by +union all

hive对group by+ union all的写法进行了优化
复制代码

2.使用 group by 来代替 distinct

在数据没有发生数据倾斜的情况下,采用distinct要比group by要好

默认情况下,distinct会被hive翻译成一个全局唯一reduce任务来做去重操作,因而并行度为1,而且有导致数据倾斜的可能。

而group by则会被hive翻译成分组聚合运算,会有多个reduce任务并行处理,每个reduce对收到的一部分数据组,进行每组聚合(去重)

注意:最新的hive版本中:新增了对count(distinct)的优化,通过配置hive.optimize.countdistinct

即使真的出现数据倾斜也可以自动优化。

3 .使用Hinit

使用mapjoin(b) 括号中指定的是数据量较小的表,表示在map阶段完成a,b两表的连接。

将原来在Reduce中进行的连接操作,前推到了Map阶段。

SELECT /* + MAPJOIN(b) */ a.key,a.value
FROM a
JOIN b ON a.key = b.key;
复制代码

大表在右边使用streamtable的sql

--STRSEAMTABLE(),括号中指定数据量大的表
--默认情况下,在reduce阶段进行连接,hive把坐标中的数据放在缓存中,右表的数据作为流数据表
SELECT /*+ STREAMTABLE(a) */ a.val,b.val,c.val
FROM a
JOIN b ON (a.key = b.key)
JOIN c ON (c.key = b.key)
复制代码

普通表的join又被称为 Replartition Join,通常shuflle操作发生在此阶段

也可以通过设置hive.smalltable.filesize or hive.mapjoin.smalltable.filesize 
如果大小表在进行连接时,小表连接小于这个默认值,则自动开启Mapjoin优化,
复制代码

六、配置的一些优化

1. 开启向量化

默认是关闭的,将一个普通的查询转化为向量化查询。大大减少了扫描,过滤等查询,标准查询时系统一次处理一行,矢量化查询可以一次性查询1024行数据,减少了系统上下文切换的开销。

set hive.vectorized.execution.enabled=true;
目前mapreduce只支持map端的向量化,tez和spark可以支持map和reduce端的向量化操作
复制代码

2. 开启并行化

--开启并行执行
set hive.exec.parallel=true;
复制代码

 ### 3. 开启map端聚合

hive.map.aggr 默认值为true
复制代码

4.调整mapTask数量

set mapred.map.tasks= task数量
复制代码

但是这个并不能完全控制mapTask数量,调节task数量需要一套完整的算法。于mapreduce的切片大小有关。 顾名思义就是将数据进行切分,切分为数据片,其实这个切片关乎于map阶段的map个数,以及每个map处理的数据量的大小。 mapreduce中,一个job的map个数, 每个map处理的数据量是如何决定的呢? 另外每个map又是如何读取输入文件的内容呢? 用户是否可以自己决定输入方式, 决定map个数呢?

mapreduce作业会根据输入目录产生多个map任务, 通过多个map任务并行执行来提高作业运行速度, 但如果map数量过少, 并行量低, 作业执行慢, 如果map数过多, 资源有限,也会增加调度开销. 因此, 根据输入产生合理的map数, 为每个map分配合适的数据量, 能有效的提升资源利用率, 并使作业运行速度加快。

1.默认情况下,Map的个数defaultNum  =目标文件或数据的总大小 totalSize/hdfs 集群文件块的大小blockSize.
2.当用户指定mapred.map.tasks,即为用户期望的Map大小,用expNum表示,但是这个值并不
    会被立即采纳。他会获取mapred.map.tasks与defaultNum的较大值,作为待定选项。
3.获取文件分片的大小和分片个数,分片大小参数为 mapred.min.split.size 和blockSize间的较大值,
    用splitMaxSize表示,将目标文件或数据总大小除以splitMaxSize 即为真是分片个数,用realSplitNum表示。
4.获取realSplitNum于expMaxNum 较小值为实际的Map个数。
复制代码

通过上面的逻辑:

减少Map个数,需要增大mapred.min.split.size的值,减少mapred.map.tasks的值
增大Map个数,需要减少mapred.min.split.size的值,增大mapred.map.tasks的值
复制代码

在之前的学习的union all案例中,单纯的减少,增大map.tasks的数量,并不能改变map个数,读者可以自行尝试。

5.调整reduce相关配置

mapred.reduce.tasks 默认值为-1,代表有系统根据需要自行决定reducer的数量
复制代码

6. 设置每个reducer能处理的数据量

hive.exec.reducers.bytes.per.reducer  设置每个reducer处理的处理量,默认256M
复制代码

7. 表示数据量需要按相同的键再次聚合,可减少重复的聚合操作

hive.optimize.reducededuplication=true;
复制代码

七、使用explain dependency查看数据输入依赖

explain dependency用于描述一段sql需要的数据来源

explain dependency 有两个使用场景

注意在使用join时,不同的join,如inner join left join中有非等值过滤条件,过滤效果不同。

场景一:快速排除 快速排除因为读取不到相应分区的数据而岛主任务数据输出异常,上游任务因为生产过程中不可控因素出现异常或者空跑,导致下游任务引发异常。

场景二:帮助清理表的输入,特别是有助于理解有多重自查询,多表连接的依赖输入。

案例:

下面有两个sql:

select a.s_no 
from student_orc_partition a
inner join student_orc_partition_only b
on a.s_no=b.s_no and a.part=b.part and a.part>=1 and b.part<=2;
复制代码
select a.s_no 
from student_orc_partition a
inner join student_orc_partition_only b
on a.s_no=b.s_no and a.part = b.part
where a.part>=1 and b.part<=2;
复制代码

通过explain dependency,其实上述的两个sql并不等价,在内连接中连接条件中假如非等值的过滤条件后,并没有将内连接的左右两个表按照过滤条件进行过滤,内连接在执行过程中会多读取part=0的分区数据

案例二:

select a.s_no 
from student_orc_partition a
leftjoin student_orc_partition_only b
on a.s_no=b.s_no and a.part=b.part and a.part>=1 and b.part<=2; 
复制代码
select a.s_no 
from student_orc_partition a
leftjoin student_orc_partition_only b
on a.s_no=b.s_no and a.part=b.part and a.part>=1 and a.part<=2; 
复制代码

通过expalin dependency,对于左外连接在连接条件中加入非等值过滤的条件,如果过滤条件是作用于右表(b表)有起到过滤效果,右表只扫描了2个分区,但是左表(a表)会进行全表扫描,

如果过滤条件是针对的是左表,则完全没有起到过滤的作用,那么两个表将会进行全表扫描。

所以通常的优化的是尽早过滤掉不需要的数据。

select a.s_no
from (
select s_no,part from student_orc_partiton
where part>=1 and part<=2
) a
left outer join student_orc_partition_only b
on a.s_no=b.s_no and a.part = b.part;    
复制代码

八、Map join的原理

一般的join 都是Repartition Join,发生在shuffle 和Reduce 阶段,如果不特殊声明,就是Repartition Join。

Map join是先启动一个作业,读取小表的数据,在内存中构建哈希表,将哈希表写入本地磁盘,然后将哈希表上传到HDFS上并添加到分布式缓存中,再启动一个任务读取表B的数据,在进行连接时Map对获取缓存中的数据并存入到哈希表中,B表会与哈希表的数据进行匹配,时间复杂度是O(1),匹配完后将结果进行输出。

一般不建议使用 hinit /*+mapjoin(b) */ 这样的用法,最坏的情况下容易发生内存溢出问题。

可以使用配置来尝试将repartition连接转化为Map连接,hive.smalltable.filesize

桶的Map 连接将普通的Map连接转化为桶连接,分桶的Hive表会将桶列的值计算Hash值取桶数的模,余数相同会发往相同的桶,每个桶对应一个文件。在两表进行连接的时候,可以快速过滤掉不要的数据,

注意使用 桶的map连接要保证连接的两张表的分桶数之前是倍数关系。

九、Skew Join倾斜连接

当有数据倾斜时的表连接。出现数据倾斜时,会引起个别任务花费大量时间和资源在处理倾斜键的数据,从而变为整个作业的瓶颈。Skew Join在工作是会将数据分为两部分,一部分为倾斜键数据,一部分是余下的所有的数据,由两个作业分别处理。

set hive.optimize.skewjoin = true;
复制代码

十、ORC与hive相关配置

orc.compress 表示orc的文件压缩类型,可选类型有NONE,ZLIB,SNAPPY

orc.bloom.filter.columns 需要创建布隆过滤的组

orc.bloom.filter.fpp 使用布隆过滤器的假正概率 默认0.05

hive中使用bloom过滤器,可以用较少的文件空间快速判定数据是否存在于表中

十一、数据倾斜

现象就是任务需要处理大量相同键的数据,这种情况有以下4中表现:

  • 数据含有大量无意义的数据,如空值(NULL)、空字符串
  • 含有倾斜数据在进行聚合计算时,无法聚合中间结果,大量数据都需要经过Shuffle阶段的处理,引起数据倾斜
  • 数据在计算时做多维数据集合,导致维度膨胀引起的数据倾斜
  • 两表进行join,都含有大量相同的倾斜数据键

1. 不可拆分大文件引发的数据倾斜

当对文件使用Gzip压缩等不支持分拣分割操作的压缩方式,当以后有作业读取压缩文件时,改文件只会被一个任务所读取,如果该压缩文件很大,则该map会成为性能瓶颈。

假如一个文件为200M,预先设置每个Map处理数据量为128M,但是计算引擎无法切分这个文件,锁这个文件不会交给两个Map任务去读取,有且只有一个Map任务在操作。

可以采用bzip2和zip等支持文件切分的压缩算法

2. 业务无关的数据引发的数据倾斜

对于空值,NULL这样的,需要在计算过程中排除这些即可。

Solution 1: Do not participate in the association with an empty user_id

select * from log a join user b on a.user_id is not null and a.user_id = b.user_id
union all
select * from log c where c.user_id is null;
复制代码

Solution 2: Assign null value to new key value

select * from log a left outer join user b on
case when a.user_id is null then concat('hive',rand()) else a.user_id end = b.user_id
复制代码

Summarize

Method 2 is more efficient than method 1. Not only is there less IO, but also the number of jobs is less. In scheme 1, the log table is read twice, and jobs must be 2, while scheme 2 is 1. This optimization is suitable for data skew generated by invalid ids (such as -99, '', null), and changes the key of the null value to

By adding a random number to a string , the data that causes the data skew can be divided into different reducers to solve the data skew problem.

Changes: All records that are null themselves will not be crowded in the same reduceTask, and will be scattered into multiple reduceTasks due to the replacement of random string values. Since the null value is not related, it will not be processed after processing. affect the final result.

1. Multi-dimensional aggregation calculation data skew caused by data expansion

For the following scenario select a,b,c count(1) from T group by a,b,c with rollup;

For the above sql, it can be split into (a,b,c),(a,b,null),(a,null,null),(null,null,null)

Method 1: Manually split this sql

Method 2: The dismantling of the job can be automatically controlled by parameters. For multi-dimensional aggregation operations such as grouping sets, rollup, and cubes, hive.new.job.grouping.cardinality will start the message if the final dismantled combination is larger than the default configuration. tasks to handle combinations other than this value

2. Data skew caused when two hive data tables are connected

When two ordinary tables perform a repartition join, if the table join key is skewed, the shuffle phase will inevitably cause data skew

Usually in this case, two jobs are still enabled. The first job processes the data without skew, and the second job stores the skewed data in the distributed cache, assigns it to the node where each Map task is located, and completes the join operation in the Map stage. Avoid shuffle, thus avoiding data skew.

Guess you like

Origin juejin.im/post/7102304965552504869