linux系统下, 在用户当前目录创建配置文件~/.hiverc, 加入配置参数
#显示头,db:
set hive.cli.print.current.db=true ;
set hive.cli.print.header=true ;
#本地模式:
set hive.exec.mode.local.auto=true ;
set hive.exec.mode.local.auto.input.files.max=10 ; #[最大文件数]
set hive.exec.reducers.bytes.per.reducer=134217728 ; #[默认128MB]
1,尽量尽早地过滤数据,减少每个阶段的数据量:where的条件写在join里面,使得减少join的数量(经过map端过滤,只输出复合条件的)
2,jion操作 小表要注意放在join的左边
3,multi insert适合基于同一个源表按照不同逻辑不同粒度处理插入不同表的场景,做到只需要扫描源表一次,job个数不变,减少源表扫描次数
#使用压缩: 输出文件压缩
SET hive.exec.compress.output=true ;
SET mapreduce.map.output.compress.codec='压缩器'
#org.apache.hadoop.io.compress.LzoCodec, org.apache.hadoop.io.compress.SnappyCodec
SET mapreduce.output.fileoutputformat.compress.type=BLOCK ;
set hive.exec.compress.intermediate=true ;#[中间压缩]
#并行处理 +jvm重用
set hive.exec.parallel=true ;
set hive.exec.parallel.thread.number=8 ; #[默认]
set mapred.job.reuse.jvm.num.tasks=1 ;#[默认]
#join查询优化: map端join[大表+小表]
#0.7之前:
set hive.auto.convert.join=true ;
#0.7之后:
set hive.mapjoin.smalltable.filesize=大小 ;
set hive.auto.convert.join=true ;
#热点数据优化:
set hive.groupby.skewindata=true ;
set hive.optimize.skewjoin=true ;
map个数:
切片大小size= max( 1, min(设置的大小,blocksize) )
map个数N=总输入数据量/ 切片大小size
#小文件太多
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
#调整map个数
set mapred.min.split.size=100000;
set mapred.max.split.size=100000000;
set mapred.min.split.size.per.node=100000000;
set mapred.min.split.size.per.rack=100000000;
reduce个数:
set mapred.reduce.tasks=x (强制指定reduce的任务数量)
set hive.exec.reducers.bytes.per.reducer=xx (每个reduce任务处理的数据量,默认为1000^3=1G)
set hive.exec.reducers.max(每个任务最大的reduce数,默认为999)
reducer数N=min( hive.exec.reducers.max ,总输入数据量/ hive.exec.reducers.bytes.per.reducer )
一般mapreduce计算的都是海量数据,map输出时候不可能把所有文件都放到内存操作,而且map输出时候要对结果进行排序,内存开销是很大的,
map在做输出时候会在内存里开启一个环形内存缓冲区,这个缓冲区专门用来输出的,默认大小是100MB,
并且在配置文件里为这个缓冲区设定了一个阀值,默认是0.80(这个大小和阀值都是可以在配置文件里进行配置的),
同时map还会为输出操作启动一个守护线程,如果缓冲区的内存达到了阀值的80%时候,这个守护线程就会把内容写到磁盘上,这个过程叫spill,
另外的20%内存可以继续写入要写进磁盘的数据,写入磁盘和写入内存操作是互不干扰的,如果缓存区被撑满了,那么map就会阻塞写入内存的操作,
让写入磁盘操作完成后再继续执行写入内存操作,前面我讲到写入磁盘前会有个排序操作,这个是在写入磁盘操作时候进行,
不是在写入内存时候进行的,如果我们定义了combiner函数,那么排序前还会执行combiner操作。
每次spill操作也就是写入磁盘操作时候就会写一个溢出文件,也就是说在做map输出有几次spill就会产生多少个溢出文件,
等map输出全部做完后,map会合并这些输出文件。这个过程里还会有一个Partitioner操作,Partitioner操作和map阶段的输入分片(Input split)很像,
一个Partitioner对应一个reduce作业,如果我们mapreduce操作只有一个reduce操作,那么Partitioner就只有一个,
如果我们有多个reduce操作,那么Partitioner对应的就会有多个,Partitioner因此就是reduce的输入分片,这个程序员可以编程控制,
主要是根据实际key和value的值,根据实际业务类型或者为了更好的reduce负载均衡要求进行,这是提高reduce效率的一个关键所在。
到了reduce阶段就是合并map输出文件了,Partitioner会找到对应的map输出文件,然后进行复制操作,复制操作时reduce会开启几个复制线程,这些线程默认个数是5个,
可以在配置文件更改复制线程的个数,这个复制过程和map写入磁盘过程类似,也有阀值和内存大小,阀值一样可以在配置文件里配置,复制时候reduce还会进行排序操作和合并文件操作.
表设计优化 | 分区表+ 桶表 |
存储优化 | 列式存储(orc, rcfile, parquet)行式存储(sequencefile) |
分区计算 | analyze【表 [分区] compute statics】 |
跟踪job | explain 【sql 语句】 |