硬刚Hive | 4万字基础调优面试小总结 – 知乎 (zhihu.com)
har小文件归档
--用来控制归档是否可用
set hive.archive.enabled=true;
--通知Hive在创建归档时是否可以设置父目录
set hive.archive.har.parentdir.settable=true;
--控制需要归档文件的大小
set har.partfile.size=1099511627776;
--使用以下命令进行归档:
ALTER TABLE A ARCHIVE PARTITION(dt='2021-05-07', hr='12');
--对已归档的分区恢复为原文件:
ALTER TABLE A UNARCHIVE PARTITION(dt='2021-05-07', hr='12');
hive调优参数
set hive.map.aggr=true; -- 开启 map 端 combiner
-- 输出合并小文件常用参数
SET hive.merge.mapfiles = true; -- 默认 true,在 map-only 任务结束时合并小文件
SET hive.merge.mapredfiles = true; -- 默认 false,在 map-reduce 任务结束时合并小文件
SET hive.merge.size.per.task = 268435456; -- 默认 256M
SET hive.merge.smallfiles.avgsize = 16777216; -- 当输出文件的平均大小小于 16m 该值时,启动一个独立的 map-reduce 任务进行文件 merge
set hive.fetch.task.conversion=more; -- 让可以不走mapreduce任务的,就不走mapreduce任务
set hive.exec.parallel=true;-- 开启任务并行执行 当一个sql中有多个job时候,且这多个job之间没有依赖,则可以让顺序执行变为并行执行(一般为用到union all的时候)
set hive.exec.parallel.thread.number=8;-- 同一个sql允许并行任务的最大线程数
set mapred.job.reuse.jvm.num.tasks=10; -- 设置jvm重用 JVM重用对hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或者task特别多的场景,这类场景大多数执行时间都很短。jvm的启动过程可能会造成相当大的开销,尤其是执行的job包含有成千上万个task任务的情况。
set mapred.reduce.tasks = 20-- 直接设置reduce数量
set hive.map.aggr=true -- map端聚合,降低传给reduce的数据量
set hive.groupby.skewindata=true -- 开启hive内置的数倾优化机制
hive 调优
hive底层的mapreduce计算引擎的调优,sql的调优,数据倾斜调优,小文件问题的调优,考虑数据本身的问题
eg1 : count(distinct age) 去重之后的年龄是很少的
-- distinct的命令会在内存中构建一个hashtable,查找去重的时间复杂度是O(1);
-- group by在不同版本间变动比较大,有的版本会用构建hashtable的形式去重,有的版本会通过排序的方式, 排序最优时间复杂度无法到O(1)。另外,第一种方式(group by)去重会转化为两个任务,会消耗更多的磁盘网络I/O资源。
-- 最新的Hive 3.0中新增了 count(distinct) 优化,通过配置 hive.optimize.countdistinct,即使真的出现数据倾斜也可以自动优化,自动改变SQL执行的逻辑。
-- 第二种方式(distinct)比第一种方式(group by)代码简洁,表达的意思简单明了,如果没有特殊的问题,代码简洁就是优!
select count(distinct col) from a;
select count(1) from (select col from a group by col) as t;
-- 推测执行优化 开启两个任务看那个先结束
set hive.mapred.map.tasks.speculative.execution=false
set hive.mapred.reduce.tasks.speculative.execution=false
set mapred.map.tasks.speculative.execution=false;
set mapred.reduce.tasks.speculative.execution=false;
--hivemap数和reduce的个数如何确定
a)假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数
b)假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数
即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。
有多少个reduce,就会有多少个输出文件
扩展优化
如果表a只有一个文件,大小为120M,但包含几千万的记录,如果用1个map去完成这个任务,肯定是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,这样就可以用多个map任务去完成。
set mapreduce.job.reduces =10;
create external table a_1 as
select * from stg_data.users
distribute by CAST(RAND() *10 AS INT);
select CAST(RAND() *10 AS INT);
这样会将a表的记录,随机的分散到包含10个文件的a_1表中,再用a_1代替上面sql中的a表,则会用10个map任务去完成。
每个map任务处理大于12M(几百万记录)的数据,效率肯定会好很多。
-- 控制map和reduce的个数
原则: 使大数据量利用合适的map数;使单个map任务处理合适的数据量
一个是要合并小文件,一个是要把大文件拆成小文件。
控制hive任务的map数
通过以下方法来在map执行前合并小文件,减少map数:
set hive.hadoop.supports.splittable.combineinputformat=true;
-- 执行map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
set mapred.min.split.size=100000000;
set mapred.max.split.size=100000000;
-- 一个节点上split的至少的大小 ,决定了多个data node上的文件是否需要合并
set mapred.min.split.size.per.node=50000000;
-- 一个交换机下split的至少的大小,决定了多个交换机上的文件是否需要合并
set mapred.min.split.size.per.rack=50000000;
参数解释
100000000表示100M
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;这个参数表示执行前进行小文件合并
mapred.min.split.size相当于mapreduce.input.fileinputformat.split.minsize,设置哪一个都一样
mapred.max.split.size相当于mapreduce.input.fileinputformat.split.maxsize,设置哪一个都一样
所以根据求splitSize的公式,return Math.max(minSize, Math.min(maxSize, blockSize));
可以知道,需增加mapper数,则减少这些值;需减少mapper数,则增加这些值,一般就配置这两个值就行了。
一般来说
max.split.size >= min.split.size >= min.size.per.node >= min.size.per.node
优先级
当四个参数设置矛盾时,系统会自动以优先级最高的参数为准,进行计算
max.split.size <= min.split.size <= min.size.per.node <= min.size.per.node
2 结果合并,下面的数值需自行调整
set hive.merge.mapfiles=true; --在Map-only的任务结束时合并小文件
set hive.merge.mapredfiles=true; --在Map-Reduce的任务结束时合并小文件
set hive.merge.size.per.task=128000000; --合并后文件的大小为128M左右
set hive.merge.smallfiles.avgsize=128000000; --当输出文件的平均大小小于128M时,启动一个独立的map-reduce任务进行文件merge
控制hive任务的reduce数
-- 控制hive任务的reduce数
reduce个数的设定极大影响任务执行效率,不指定reduce个数的情况下,Hive会猜测确定一个reduce个数,基于以下两个设定:
hive.exec.reducers.bytes.per.reducer--(每个reduce任务处理的数据量,默认为1000^3=1G)
hive.exec.reducers.max --(每个任务最大的reduce数,默认为999)
-- eg:
输入数据量 130M
每个reduce处理的数据量 64M
reduce个数:reducer数=min(1099,130m/64m)=3
有多少个reduce,就会有多少个输出文件
-- 调整reduce个数:
-- 调整hive.exec.reducers.bytes.per.reducer参数的值;
set hive.exec.reducers.bytes.per.reducer=500000000; (500M)
-- 直接设置reduce的值
set mapred.reduce.tasks = 15;
使大数据量利用合适的reduce数;使单个reduce任务处理合适的数据量
动态分区属性
动态分区属性:设置为true表示开启动态分区功能(默认为false)
hive.exec.dynamic.partition=true;
动态分区属性:设置为nonstrict,表示允许所有分区都是动态的(默认为strict) 设置为strict,表示必须保证至少有一个分区是静态的
hive.exec.dynamic.partition.mode=strict;
动态分区属性:每个mapper或reducer可以创建的最大动态分区个数
hive.exec.max.dynamic.partitions.pernode=100;
动态分区属性:一个动态分区创建语句可以创建的最大动态分区个数
hive.exec.max.dynamic.partitions=1000;
动态分区属性:全局可以创建的最大文件个数
hive.exec.max.created.files=100000;
数据建模 维度建模
星型模式是以事实表为中心,所有的维度表直接连接在事实表上,像星星一样。星形模式的维度建模由一个事实表和一组维表成,
a. 维表只和事实表关联,维表之间没有关联;
b. 每个维表主键为单列,且该主键放置在事实表中,作为两边连接的外键;
c. 以事实表为核心,维表围绕核心呈星形分布。
雪花模型
雪花模式(Snowflake Schema)是对星型模式的扩展。雪花模式的维度表可以拥有其他维度表的,虽然这种模型相比星型更规范一些,但是由于这种模型不太容易理解,维护成本比较高,而且性能方面需要关联多层维表,性能比星型模型要低。
星座模型
星座模式是星型模式延伸而来,星型模式是基于一张事实表的,而星座模式是基于多张事实表的,而且共享维度信息。前面介绍的两种维度建模方法都是多维表对应单事实表,但在很多时候维度空间内的事实表不止一个,而一个维表也可能被多个事实表用到。在业务发展后期,绝大部分维度建模都采用的是星座模式。
[map,reduce优化]: https://blog.csdn.net/qq_46893497/article/details/113864209
```sql
order by 会对输入做全局排序,因此只有一个reducer,会导致当输入规模较大时,需要较长的计算时间。
sort by不是全局排序,其在数据进入reducer前完成排序,如果设置mapred.reduce.tasks>1, 则sort by只保证每个reducer的输出有序,不保证全局有序。
Distribute by:按照指定的字段对数据进行划分输出到不同的reduce中。
Cluster by:除了具有 distribute by 的功能外还兼具 sort by 的功能。
UDF:单行进入,单行输出
UDAF:多行进入,单行输出
UDTF:单行输入,多行输出
sum_data(聚合)
ods_data()
pdm_data()
版权声明:本文为wenwen1542原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。