优化的中心思想
以Hive On MapReduce 为例(Hive On Spark等思路也是一致的)
HiveSQL的优化,本质是对MapReduce作业的优化
HiveSQL会最终转化为MapReduce进行执行. 所以优化的根本依据是了解HiveSQL会转化成怎样的MR作业以及MR作业的一些特点
MapReduce的一些特点
- 数据读取和写入,都是针对HDFS(磁盘)而言,都是IO操作
- 不喜欢某一个任务过大(数据倾斜).一个经典的结论:数据量不是问题,数据倾斜才是
- 不喜欢大量过小的任务.任务资源申请等本身初始化和管理也是需要消耗时间和资源得.大量过小任务,导致时间和资源都花在任务维护上了
所以在HiveSQL上,也是针对这些特点来进行优化
一些优化的思路
IO方向
只查询需要的列
MapReduce会根据查询谓词裁剪列,简单说就是不查询的列不读,这样可以降低IO
尽可能的使用表分区
表分区条件后,MapReduce会直接跳过不需要的分区的全部文件,极大的降低IO
数据倾斜
慎用count(distinct)
慎用count(distinct)原因是容易造成数据倾斜 可以考虑换GroupBy子查询
count(distinct) 其执行的MR=>以GroupBy分组,再对distinct列排序,然后输出交给Reduce
相比其它GroupBy聚合统计,count(distinct)少一个关键步骤(Map的提前聚合)
当Map直接将全部数据交给Reduce后,如果数据的分组本身不平衡(比如及格,80%以上及格数据)
会造成某一些Reduce处理太过多的数据,这就是数据倾斜
注意null值带来的数据倾斜
业务上考虑是否能做过滤
否则就考虑将null值提出单独处理,单独处理时加入随机打散Map,以避开数据倾斜
所有null会认为是同一个值,走同一个Map,如果null占的比重一大,又是一个数据倾斜.
这里同样适用其它的业务null值(比如常见的0,1,-1,-99等业务默认值)
数据倾斜是个大问题,后面单章描述
表关联
大表放后
因为join的前一阶段生成的数据会存在于Reducer的buffer中,小表数据量小,内存开销就小,与后面的大表进行连接时,只需要从buffer中读取缓存的Key,与大表中的指定Key进行连接,速度会更快,也可能避免内存缓冲区溢出
同列关联
如可能,尽可能用同一列关联
同列关联,无论关联多少表都是一个Map搞定,如果不是同列,就会新开一个MapReduce
考虑列式存储
考虑存储文件格式为列式存储,例如ORC,Parquet等等,Hive中推荐使用ORC
列式存储在处理列裁剪和谓词下推时有相当大的优势
配置
MapReduce或Spark配置