具体细节见前文Hive调优和原理篇
四大调优方向
1 建表设计层面 2 HQL语法和运行参数层面 3 HIVE架构层面 4 HIVE数据倾斜
一 建表设计层面
谈分区分桶表,如join字段可以用分桶表。 合理的文件格式, 输出结果/中间结果数据压缩 位数组优化存储方式
二 HQL语法和运行参数层面
10万+数量一个reducetask足够,合理设计task并行度
主动开启列裁剪,只读需要的列
合并小文件:map输入数据有两种方式(一种合并小文件默认128mb,一种不合并文件)
join的优化: 1 小表无脑用mapjoin,小表数据分发存入各节点内存中,map阶段直接join,默认内存25mb 2 join的数据倾斜可以用skewjoin,根据skewjoin设置的参数阈值拆分大key,默认10万。 3 主动开启谓词下推,where提前执行减少下游处理量。如join x where x,会改成先where条件过滤后再join 4 (建表层面:分桶也可以提高join效率) 5 CBO成本优化器,照执行成本最小的来选择合适的join算法 6 随机id打散大表:大表加随机数id如1-4,小表数据扩容成4倍文件并各自加上id 1-4。 之后大表和小表通过id join,就可以把1个reduceTask变成4个redcueTask,修改提高并行执行参数(默认8)
groupby优化: map端设定行数阈值拆分job做预聚合,然后最终大合并 主动开启map预聚合两个参数:1 参数true开启 2 map端行数阈值则拆分map聚合job
order by/count/distinct优化: 一个job sql可以拆分多个job执行,如count(distinct),因为distinct去重只有一个reduce task,可改为先group by后再count(1) 如count (distinct a)group by b可以改成先group by a,b然后group by b,最后直接count a。另外可以设置参数自动拆分distinct
in/exist 语法改写 semi join,也可以用布隆过滤器判断数据是否在表中 union:grouping sets代替union,多次读表变一次读
三 HIVE架构层面
1 select *等不涉及计算可以不调用mr,直接hive主动开启本地抓取模式 2 JVM重用,可改参数由一个jvm执行一个task改成一个jvm串行复用的执行多个个task 3 并行执行 随机id打散大表:大表加随机数id如1-4,小表数据扩容成4倍文件并各自加上id 1-4。 之后大表和小表通过id join,就可以把1个reduceTask变成4个redcueTask,提高并行执行性能 4 推测执行,根据一定法则推测出性能低下的task,给这种task多执行一个备份task,最后取运算最快的task结果 5 严格模式
四 Hive实现原理
1 join select a.age from a join b on a.id = b.id 遍历a表id为key,age+id为value。遍历b表同理,最后通过id连接两表数据 2 groupby key a,key b 局部<a,b> 为key,如求count时则key出现的数量为value,最后全局汇总 3 exists/case when/where/having等就是if else过滤 4 distinct 通过groupby分组聚合,也有hash去重的实现方式
count计数的聚合模式 ·count(列):如果列中有null值,那么这一列不会被记入统计的行数。 另外,Hive读取数据进行计算时,需要将字节流转化为对象的序列化和反序列化的操作。
·count(*):不会出现count(列)在行是null值的情况下,不计入行数的问题。
另外,count(*)在进行数据统计时不会读取表中的数据,只会使用到HDFS文件中每一行的行偏移量。
该偏移量是数据写入HDFS文件时,HDFS添加的。
·count(1):
count(*)也包含NULL,如果表没有主键,那么count(1)比count(*)快。
表有主键,count(*)会自动优化到主键列上。如果表只有一个字段,count(*)最快。
count(1)跟count(主键)一样,只扫描主键。count(*)跟count(非主键)一样,扫描整个表。明显前者更快一些。
count(1)和count(*)基本没有差别,但在优化的时候尽量使用count(1)
|