Hive的相关优化点

1.Hive相关函数说明

  • if函数
    • 格式: if(boolean testCondition, T valueTrue, T valueFalseOrNull)
    • 说明: 当参数1的条件成立时候, 返回参数2的数据, 否则返回参数3的数据
  • nvl函数:
    • 格式: nvl(T value, T default_value)
    • 说明: 空值替换, 当参数1为null的时候返回参数2的数据,否则返回参数1的数据
  • COALESCE函数:
    • 格式: coalesce(T v1, T v2,T v3,…)
    • 说明: 返回在参数中第一个不为null的值,只有当所参数都为null的时候返回null
    coalesce('张三',null,null,'李四')   --返回张三
    coalesce(null,null,'王五','赵六')   --返回王五 
    
  • CASE WHEN THEN 条件判断函数:
    • 格式:
      • case a when b then c [when d then e]* [else f ] end
        • 说明: 当a=b的时候返回c,当a=d的时候返回e,否则返回f
      • case when a then b [when c then d]* [else e] end
        • 说明: 当a条件满足时,返回b,当c条件满足时,返回d, 否则返回e
  • isnull() 和 isnotnull()
    • 格式: isnull(a) || ianotnull(b)
    • 说明: isnull 是用于判断某一数据是否为null, 如果为null就会返回true 否则返回false , isnotnull()正好与之相反

2.Hive的基本优化

  • hive的并行优化
1.1) hive的并行编译执行(建议直接在CM上进行通用配置)
	相关参数:
		hive.driver.parallel.compilation :  是否开启并行编译, 默认为false
		hive.driver.parallel.compilation.global.limit  运行同时编译几条SQL, 默认为3
	说明:
		hive是可以开启多个会话进行相关操作,但是在默认情况下(默认是并行关闭的),hive在同一时间,只能对某一会话下的SQL进行编译,无法对多个会话提交的SQL进行同时编译操作;
		开启并行编译后, 允许hive对多个会话提交的SQL进行同时编译操作, 压缩执行时间来提升效率
1.2) hive的并行执行操作(会话中配置)
	相关参数
		set hive.exec.parallel=true;   是否开启hive的并行执行操作, 默认为false
		set hive.exec.parallel.thread.number=16;   一次性允许多少个阶段同时执行, 默认为8
	说明:
		在一条SQL语句中,一个SQL执行计划可能会被翻译成多个阶段(多个MR), 多个阶段之间可能没有任何关联(没有依赖关系),此时可以将这些阶段同时运行,从而提升效率, 默认情况下,不管是否存在依赖关系, 都是从上往下按照执行计划, 依次执行各个阶段
	例如:
		select * from (select * from a group by name) as tb1 left join (select * from b group by name) as tb2 on tb1.t_id = tb2.t_id;
	说明:
		在join的左右两边是两条SQL语句,这两个SQL语句执行没有任何依赖关系, 此时可以将两个SQL同时执行,以提升效率;
  • Hive的小文件合并优化(CM上配置)
    直接在CM上进行通用配置操作
思考: 小文件过多会有什么问题?
	HDFS: 在HDFS中如果小文件过多,每一个文件都会有一个元数据信息,而元数据信息是存储在namenode的内存中,过多文件会导致namenode的内存爆满,从而影响整个HDFS的存储容量;
	MR: 当小文件过多后,MR在读取这些文件的时候,由于一个文件需要至少一个逻辑分片,此时多个文件就会被分为多个文件切片,从而导致MR需要启动多个MapTask, 而每个MapTask处理数据量极少,从而导致大量的时间都浪费在申请资源过程,导致MR执行效率低下,如果资源不足,多个MapTask只能串行执行,从而效率更低;
解决方案: 让MR在输出文件的时候, 不要输出过多的文件项, 如果小文件过多, 让MR自动合并处理
	hive.merge.mapfiles  : 是否开启map端的小文件合并的操作  默认为true
	hive.merge.mapredfiles : 是否开启reduce端的小文件合并操作  默认为false
	hive.merge.size.per.task : 合并后MR输出文件的大小,默认为256M。
	hive.merge.smallfiles.avgsize : 当输出文件的平均大小小于此设置值时,启动一个独立的map-reduce任务进行文件merge,默认值为16M。
	
	例如: 假设reduce输出的文件有以下五个,其大小分别:  10M  8M 100M  1M 2M  此时不会触发合并操作, 因为平均值没有低于16M

	例如: 假设reduce输出的文件有以下五个,其大小分别:  3M 15M 35M 3M 7M 
		此时输出的文件平均值低于16M ,自动触发合并成操作, 对文件进行合并: 合并为一个  63M文件
	
	例如:  合并后文件最大为 80M , 此时 reduce输出文件有以下:   3M 15M 35M 3M 7M  30M  30M  10M
    	此时输出的文件平均值低于16M ,自动触发合并成操作, 对文件进行合并: 
    		此时会合并为二个文件: 
    			一个文件为 80M  另一个  53M
  • 矢量化查询
 hive的默认查询执行引擎一次处理一行,而矢量化查询执行是一种hive特性,目的是按照每批1024行读取数据,并且一次性对整个记录整合(而不是对单条记录)应用操作,注意:要使用矢量化查询执行,就必须以ORC格式存储数据。
    
参数:
	set hive.vectorized.execution.enabled=true; 默认为true
  • 读取零拷贝
在执行SQL的时候, 如果SQL中对应表中有  没有使用到的字段 在读取的时候, 没有必要将这些不使用字段读取到内存中,  此时可以通过开启读取零拷贝来实现此项功能:
	set hive.exec.orc.zerocopy=true;
	
	注意: 前提表的存储格式必须为ORC

3.Hive的数据倾斜问题处理

思考1: 一般发生数据倾斜主要在什么位置上呢?  group by  和  join 操作

思考2: 为什么数在这两种情况下, 发生倾斜比较高呢? 
	原因:  
		group by: 在执行分组的时候 , 为了提升效率, reduce可以运行多个, 此时只需要保证相同key发往同一个reduce即可, 此时如果某个key数据量远远大于其他的数据量此时某一个reduce接收数据量就会比较高, 此时就会发生数据倾斜
		join: 在执行普通的reduce端join的时候, 同样reduce也是可以有多个一起执行join的, 需要保证join字段上,相同key必须发往同一个reduce,  此时如果join字段的某个值非常多, 此时也容易导致数据倾斜
		

如何解决呢? 
  • Join 数据倾斜的解决
解决方案:
	方案一: 采用 map join 或者  bucket map join  或者 SMB join
		虽然方案一可以解决倾斜问题, 但是并不能解决所有的join倾斜问题, 因为map join都是由使用条件的, 如果条件不满足, 那么无法使用
	方案二: 将那些容易产生倾斜的key 从整个翻译后MR中剔除出去, 单独找一个MR运行处理即可, 最后将这个新的MR的处理结果和 原有MR处理结果进行合并即可
		运行期处理: 适合于不清楚那个值会产生数据倾斜
			set hive.optimize.skewjoin=true;  默认为false  是否开启运行期数据倾斜解决操作
			set hive.skewjoin.key=100000;  当key的相同值达到多大数量的时候, 认为发生了倾斜
			说明:
				一旦开启运行期解决数据倾斜后, 整个MR会自动记录相同k2的数量, 当这个数量到达一定的阈值后, 认为这个k2的值产生数据倾斜, 自动将这个k2的对应所有的数据剔除出去, 找一个单独的MR进行处理
		
		
		编译期处理: 适合于清楚知道表中那些字段的值会产生数据倾斜
			set hive.optimize.skewjoin.compiletime=true; 默认关闭的  编译期解决数据倾斜
			
            开启后, 还需要在创建表的时候, 提前的预知将那些容易产生倾斜的key设置到表的元数据中
            CREATE TABLE list_bucket_single (key STRING, value STRING)
            -- 倾斜的字段和需要拆分的key值
            SKEWED BY (key) ON (1,5,6)
            --  为倾斜值创建子目录单独存放
            [STORED AS DIRECTORIES];

			在运行的时候, 只要将对应字段当做join的字段时候, 此时执行时候, 自动将 字段= 1 或者 5 或者  6的数据, 直接剔除出去, 交给一个新的MR处理接口
		
思考: 在实际使用中, 需要配置那个呢?  建议两个都配置
	原因:
		很多时候, 对表的了解程序没有那么高(甚至可以说没有任何一个人对表哟非常清晰的了解), 一般如果找到那些key有倾斜, 可以通过编译期解决, 其他不知道的, 通过 运行期动态捕获即可


注意: 不管运行期还是编译期, 最终都会执行多个MR操作, 每个MR都会产生局部的结果, 最后将局部结果进行汇总合并形成最终结果操作 (注意: 合并操作也是需要运行一个MR)

union all的优化, 主要和 join的倾斜配合使用, 提升union all的效率
为了提升最终多个MR的合并效率, 可以开启以下参数:
	set hive.optimize.union.remove=true; 
	一旦开启后, 合并操作直接省略(省略一个MR执行),多个MR将各个局部结果直接输出到目的地即可
  • Group by的数据倾斜
解决方案:
	方案一: 开启map端combiner的操作(map端局部聚合操作), 这样可以减少从map端到reduce的数据量, 从而减轻倾斜压力
		参数: hive.map.aggr=true;  开启map端局部聚合操作  (建议直接在CM上配置常开)
	方案二: 负载均衡,本质上是一个大的conbiner的操作, 通过两个MR解决, 第一个MR主要负责将所有的数据均衡发往各个各个reduce中, 保证每个reduce得到的数据量基本相同(负载均衡过程), 每一个reduce进行聚合操作 (此时仅仅是一个局部聚合) 接下来将第一个MR统计结果, 作为第二个MR的输入, 第二个MR根据相同key发往同一个reduce, 进行最终统计计算即可
		参数: hive.groupby.skewindata=true; (建议在会话中配置)
		

注意事项: 当使用方案二的时候, SQL在编写的有一个注意事项
	在多个列上进行的去重操作与hive环境变量hive.groupby.skewindata存在冲突。

(1) SELECT count(DISTINCT uid) FROM log
(2) SELECT ip, count(DISTINCT uid) FROM log GROUP BY ip
(3) SELECT ip, count(DISTINCT uid, uname) FROMlog GROUP BY ip
(4) SELECT ip, count(DISTINCT uid), count(DISTINCT uname) FROMlog GROUP BY ip

123能够正常执行,但是4会报错。

报错内容:
	Error in semantic analysis: DISTINCT on different columns notsupported with skew in data.

思考: 如何知道SQL会发生数据倾斜呢? 查看整个SQL执行的MR中,每一个reduce的执行时间 , 如果某一个或者某几个reduce的执行时间远远大于其他的reduce, 认为此SQL发生数据倾斜
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.关联优化器

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

set hive.optimize.correlation=true;  -- 共享shuffle

例子:
	select 
		tmp1.category,
		tmp1.max,
		time2.min
	from 
		(select category, max(price) as max from order group by category) as tmp1
		join
		(select category, min(price) as min from order group by category) as tmp2
		on tmp1.category = tmp2.category

5. 总结

set hive.exec.parallel=true; 是否开启hive的并行执行操作  默认值为false
set hive.exec.parallel.thread.number=16; 一次性允许多少个阶段同时执行 默认值为 8
set hive.exec.orc.zerocopy=true; -- 开启读取零拷贝
set hive.optimize.skewjoin=true;  默认为false  是否开启运行期数据倾斜解决操作
set hive.skewjoin.key=100000;  当key的相同值达到多大数量的时候, 认为发生了倾斜
set hive.optimize.skewjoin.compiletime=true; --开启编译期解决join数据倾斜
set hive.groupby.skewindata=true; -- 负载均衡优化
set hive.optimize.correlation=true;  -- 关联优化器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值