1.基础优化
1.1 hive并行操作
- Hive编译查询限制 : (一般是作为通用配置: cm的hive上面)
- 说明: Hive默认同时只能编译一段HiveQL,并上锁
如何解决多个会话时, 同时只能有一个会话进行编译的问题 ?
hive.driver.parallel.compilation 设置为true 是否开启一次性编译多个sql的功能 默认为 false
hive.driver.parallel.compilation.global.limit 默认值为3 表示一次性最多同时有三个会话进行编译sql
注意: 如果此值设置为 0 表示无边界, 此值是否会生效取决于第一个参数是否设置为true
- Hive不同阶段任务并行执行 : (一般是进行单独会话配置)
- 说明: Hive会将一个查询转化为一个或多个阶段,包括:MapReduce阶段、抽样阶段、合并阶段、limit阶段等。默认情况下,一次只执行一个阶段。不过,如果某些阶段不是互相依赖,是可以并行执行的。
set hive.exec.parallel=true; 默认值为false 表示是否要开启hive的并行执行
set hive.exec.parallel.thread.number=16; 表示一次性一个sql中最大运行并行的数量 默认值8
1.2 hive的小文件合并
- hive在执行的sql的时候, 会将sql翻译为MR来执行, MR的读取目标数据的时候, 如果目标数据中有大量的小文件, 此时就会导致启动多个mapTask来执行, 此时对系统资源是一种极大的浪费, 导致执行效率降低
- reduce小文件过多会有什么影响?
1.对HDFS不友好
2 下次对结果表进行操作, 又会小文件过多的问题 - 解决方案: 在读取数据的时候, 对目标数据进行小文件合并, 将其合并为一个较大的文件 从而减少mapTask的数量
hive.merge.mapfiles : 是否开启 map端的小文件合并的操作: 默认值为 true
hive.merge.mapredfiles: 是否要开启reduce的输出小文件合并 : 默认值为false
hive.merge.size.per.task: 表示合并后的文件的大小 默认值为 268435456(256M)
hive.merge.smallfiles.avgsize: 表示当输出文件的平均大小小于此设置值时,启动一个独立的map-reduce任务进行文件merge,默认值为16M。
注意: 以上调整的参数, 均可以直接在CM上调整操作
1.3 hive的矢量化查询
- hive的默认查询执行引擎一次处理一行,而矢量化查询执行是一种hive特性,目的是按照每批1024行读取数据,并且一次性对整个记录整合(而不是对单条记录)应用操作,也可以理解为批量化操作
set hive.vectorized.execution.enabled=true; 默认就是true 是否开启批量化查询
注意事项:要求读取的表的数据格式为ORC
1.4 读取零拷贝
- 在读取HDFS的数据的时候, 只需要将需要的数据读取到内存中, 不需要的数据, 就不进行读取操作
- 注意事项: 如果想要实现此功能, 要求表的数据格式 ORC
set hive.exec.orc.zerocopy=true; 默认值为false
示例:
A 表中 b c d 三个字段
执行以下操作:
select b,c from A where b= '' ; 在开启读取零拷贝的情况下, 读取数据的时候, 只需要将表中 b和c这两列的数据读取到内存中即可
- 总结
set hive.driver.parallel.compilation=true
set hive.driver.parallel.compilation.global.limit=3
set hive.exec.parallel=true;
set hive.exec.parallel.thread.number=16;
set hive.exec.orc.zerocopy=true;
2.数据倾斜优化
2.1 数据倾斜的原因和导致数据倾斜的操作
- 出现数据倾斜原因:map输出数据按key Hash的分配到reduce中,由于key分布不均匀、业务数据本身的特性、建表时考虑不周、等原因造成的reduce 上的数据量差异过大。
- key分布不均匀;
- 业务数据本身的特性;
- 建表时考虑不周
- 某些SQL本身导致的数据倾斜
- 在进行join、group by操作的时候会导致数据倾斜
2.2 解决数据倾斜的方案
2.2.1 解决数据倾斜-join倾斜
- 解决方案一:通过mapjoin bucket mapjoin和smb join解决
- 小表和大表join,使用map join
- map join 不局限于任何类型表
map join原理:运行时直接将小表加载到内存中,在map端完成join操作
缺点:加大内存占用,如果内存不足,容易造成内存泄漏,只适用于小表和大表关联
开启map join方法:
set hive.auto.convert.join=true; -- 是否开启 map join 工作
set hive.auto.convert.join.noconditionaltask.size=512000000; -- 设置小表临界值大小 默认值: 20M
- 中型表和大表关联,使用bucket mapjoin
使用要求:
1)必须开启bucket map join支持: set hive.optimize.bucketmapjoin = true;
2)一个表的bucket数是另一个表bucket数的整数倍
3)bucket列 == join列
4)必须是应用在map join的场景中
5) 表必须是分桶表
- 大型表和大型表关联,使用smb(Sort merge Bucket) mapjoin
满足条件:
1)必须开启bucket map join支持: set hive.optimize.bucketmapjoin = true;
2)一个表的bucket数等于另一个表bucket数
3)bucket列 == join列 == sort列
4)必须是应用在bucket map join的场景中
5) 表必须是分桶表
-- 启动桶表
set hive.enforce.bucketing=true;
-- 保证必须进行强制排序操作
set hive.enforce.sorting=true;
-- 开启 bucket map join
set hive.optimize.bucketmapjoin = true;
-- 开启 SMB join
set hive.auto.convert.sortmerge.join=true;
set hive.auto.convert.sortmerge.join.noconditionaltask=true;
-- 是否自动尝试使用SMB join 连接 可以直接在CM中配置
set hive.optimize.bucketmapjoin.sortedmerge = true;
如何保证, 分桶表中,按照分桶字段进行排序呢?
第一步: 建表的时候
create table test_smb_2(mid string,age_id string)
CLUSTERED BY(mid) SORTED BY(mid) INTO 500 BUCKETS;
第二步: --写入数据强制排序
set hive.enforce.sorting=true;
- 解决方案二:将那些容易产生数据倾斜的key值抽取出来, 使用一个单独的MR进行处理即可
- 实施方案一: 运行时优化
- 说明:
在运行的过程中, 时刻监控着k2的值, 当k2中某个值出现的次数大于设置的值, 认为此值出现数据倾斜, 将其单独存储起来, 通过一个单独的MR对其进行单独处理即可 - 注意: 此种优化, 如果数据中 大多数key都大于了此值, 如果要使用这个优化, 需要调整hive.skewjoin.key此值大小
- 配置:
set hive.optimize.skewjoin=true; 开启 运行时的join数据倾斜优化
set hive.skewjoin.key=100000; 当这个key的值出现多少个的时候, 认为是有数据倾斜的问题
- 实施方案二: 编译时优化
- 整体优化思想都是一样的, 只不过编译时优化在编译器形成执行计划的时候, 就已经优化完毕了
- 注意: 在执行之前,或者建表之前, 就需要指定那些key的值会导致数据倾斜
- 配置:
set hive.optimize.skewjoin.compiletime=true; 默认关闭
--建表示例:
CREATE TABLE list_bucket_single (key STRING, value STRING)
-- 倾斜的字段和需要拆分的key值
SKEWED BY (key) ON (1,5,6)
-- 为倾斜值创建子目录单独存放
[STORED AS DIRECTORIES];
在具体使用时候, 可以两个都开启为true, 这样当出现了编译期设置的key值, 直接就进行优化了, 如果是编译期没有考虑到的值, 在运行过程中, 发现了, 也可以进行优化处理
2.2.2 union all的优化
- 在进行join的数据倾斜优化的时候, 不管采用 运行时的, 还是编译时, 都是将能产生倾斜的key值, 单独拿出来, 使用一个单独MR进行处理, 处理后和之前结果进行union all 合并操作
- 正常情况下, union all 也需要单独运行一个MR, 将两个结果进行合并, 出现到一个目标目录下,而再增加一个MR,也会对效率产生影响
- 解决方案:不执行union all,直接让新产生的MR的结果输出到目的地
- 配置:
set hive.optimize.union.remove=true;
2.2.3 解决数据倾斜-group by倾斜
- 方案一:小规约 开启 map端的局部聚合操作
- 配置: hive.map.aggr=true;
- 方案二: 大规约 运行两个MR , 第一个MR 进行局部聚合操作, 第二个MR 进行最终聚合操作
- 配置:hive.groupby.skewindata=true;
- 注意事项:
如果使用方案二进行group by 数据倾斜的解决, 要求sql中不允许出现多次distinct操作, 只能出现一次
例如:
SELECT ip, count(DISTINCT uid), count(DISTINCT uname) FROMlog GROUP BY ip
此操作 就会直接报错, 因为此sql中出现多次distinct操作
报错内容: DISTINCT on different columns notsupported with skew in data.
3 关联优化器
- 在hive执行sql的时候, 一个sql翻译的MR中可能会出现多次shuffle操作, 而多次的shuffle操作有可能是可以共享的, 此时就可以将shuffle进行共享, 从而减少shuffle次数, 从而提升效率
- 配置:set hive.optimize.correlation=true;
总结
set hive.driver.parallel.compilation=true
set hive.driver.parallel.compilation.global.limit=3
set hive.exec.parallel=true;
set hive.exec.parallel.thread.number=16; -- 以上四个是hive的并行优化
set hive.merge.mapfiles = true ; -- 开启hive的map端小文件合并
set hive.merge.mapredfiles= true; -- 开启hive的reduce端小文件合并
set hive.exec.orc.zerocopy=true; -- hive的读取零拷贝
set hive.vectorized.execution.enabled=true; -- hive的矢量化的查询优化
set hive.optimize.correlation=true; -- hive的关联优化器
set hive.optimize.skewjoin=true;
set hive.optimize.skewjoin.compiletime=true; -- hive的 join的数据倾斜的优化
set hive.optimize.union.remove=true; -- hive union all的优化方案
set hive.map.aggr=true;
set hive.groupby.skewindata=true; -- hive的 group by 数据倾斜的优化