注:下文中输入数据大小指的是desc formatted 表名返回的rawDataSize,文件个数为返回的numFiles
1. 不跑MR程序进行数据抽取
配置项:hive.fetch.task.conversion
| 取值 | 描述 |
|---|---|
| more | 默认值,SELECT, FILTER, LIMIT only (including TABLESAMPLE, virtual columns, UDF, 表达式) |
| minimal | SELECT *, FILTER on partition columns (WHERE and HAVING clauses), LIMIT only |
| none | 禁用该功能,执行MR |
2. 小任务本地执行
配置项:hive.exec.mode.local.auto,默认为false,开启后,MR转本地执行,还需满足下表的配置项
| 配置 | 默认值 | 描述 |
|---|---|---|
| hive.exec.mode.local.auto.inputbytes.max | 134217728,即128MB | 开启MR转本地执行时,输入数据大小的最大值 |
| hive.exec.mode.local.auto.tasks.max | 4 | 开启MR转本地执行时,map任务数最大值 |
| hive.exec.mode.local.auto.input.files.max | 4 | 开启MR转本地执行时,输入文件个数的最大值 |
3. map join
配置项:hive.auto.convert.join,默认为true,需满足下表的配置项
| 配置 | 默认值 | 描述 |
|---|---|---|
| hive.mapjoin.smalltable.filesize | 25000000,即25MB | 当rawDataSize小于该值时,可以使用mapjoin |
| hive.auto.convert.join.noconditionaltask | true | 多个map join转成一个map join |
| hive.auto.convert.join.noconditionaltask.size | 10000000,即10MB | 多个join的小表的大小总和不超过该值 |
map join过程
- Local work:
- 将表中的数据读到本地
- 构建hash表
- 将hash表序列化到本地
- 上传本地文件到hdfs
- 将文件添加到分布式缓存
- Map task
- 在内存中序列化生成hash表
- 对大表中的数据一条条进行匹配
-- 合并匹配的数据并输出
4. bucket map join
要求:关联字段是分桶字段,且两张表的分桶字段类型相同,桶的个数成倍数关系。
| 配置 | 默认值 | 描述 |
|---|---|---|
| hive.auto.convert.sortmerge.join | false | 是否将桶的join自动转成map join |
| hive.optimize.bucketmapjoin | false | 是否开启bucket map join |
| hive.optimize.bucketmapjoin.sortedmerge | false | 是否将Sort-Merge-Bucket (SMB) joins 转成SMB map joins |
| hive.auto.convert.sortmerge.join.bigtable.selection.policy | org.apache.hadoop.hive.ql.optimizer.AvgPartitionSizeBasedBigTableSelectorForAutoSMJ | 大表选择策略,共3种 |
5. groupby 相关优化
- 配置:hive.groupby.skewindata,默认为false
- 为true,会增加一个MR,第一个MR用来将key随机化,然后聚合,第二个MR使用真正的key聚合,由于第一个MR已经聚合了一部分数据,这样避免数据倾斜
-
hive.map.aggr
- 默认为true,开启map端聚合
-
hive.groupby.mapaggr.checkinterval
- 默认为100000条,map端聚合使用hash表来聚合,当读取的数据达到了该值,则会检查一下是否需要溢写
-
hive.map.aggr.hash.percentmemory
- 默认为0.5,当map端聚合使用hash表的内存超过了堆内存的该比例时,则溢写到磁盘
6. count(distinct)
当id数据倾斜时或表数据量较大时,将count(distinct id)改成
select count(1) from (select id from t group by id) t
7. 小表join大表
这里的小表不是指的map join类型的小表,而是关联key在这个表中没有倾斜,同理大表指的是关联key存在倾斜。遇到这样的表进行join,需要把小表放在左边。原因与hive表的join实现有关:
- map端,输出的key为关联key与tag的组合键,tag表示数据来源,左边的表的tag小,分组按原始的key,排序使用组合键;输出的value也是tag与原始value的组合
- reduce端,经过排序后,对相同的key,左边表的数据会先获取到,放入到内存中,右边的表是读一条,关联内存中的左表数据,输出
- 假设大表放到左边,由于它的记录被放入到了内存,数据倾斜可能导致OOM
对于这样的情况,还有一种是使用skewed table并使用list bucketing,笔者的上篇文章hive总结已经有讲,注意要配置hive.optimize.skewjoin.compiletime=true,这个选项的意思是在编译生成执行计划时,会使用skewed table的元数据来对倾斜的key做优化。
还有一个配置hive.optimize.skewjoin,它会在reduce端统计数据倾斜的key,当相同key超过hive.skewjoin.key(默认100000),则认为该key倾斜,此时hive会启用另一个map join来处理倾斜的key
8. 大表join大表
大表指的是关联key存在倾斜(没有无效KEY)。对于这种情况,有一种解决方式是使用skewed table并使用list bucketing或者启用hive.optimize.skewjoin,由于它们的处理方式都是最后进行map join,需要将一张表的部分数据放入到内存,假设极端情况下,放入到内存的表的相同key也倾斜,导致放入到内存会引起OOM,这时有一种思路是将这张表倾斜的数据切分为若干块,将这一块加载到内存与另一张表中倾斜的数据进行map join,这样并行处理分成的若干块。
9. 其它
- 并行执行
- 推测执行
- 对无效KEY进行过滤或加上随机值