在企业中使用Hive构建离线数仓是一种十分普遍的方案。尽管Hive的使用场景是通过批处理的方式处理大数据,通常对处理时间不敏感。但是在资源有限的情况下,我们需要关注Hive的性能调优,从而方便数据的快速产出。同时,关于Hive的性能调优,也是面试中比较常见的问题,因此掌握Hive性能调优的一些方法,不仅能够在工作中提升效率而且还可以在面试中脱颖而出。本文会通过四个方面介绍Hive性能调优,主要包括:
√性能调优的工具
√设计优化
√数据存储优化
√作业优化
性能调优的工具
HQL提供了两个查看查询性能的工具:explain与analyze,除此之外Hive的日志也提供了非常详细的信息,方便查看执行性能和报错排查。
善用explain语句
explain语句是查看执行计划经常使用的一个工具,可以使用该语句分析查询执行计划,具体使用语法如下:
EXPLAIN [FORMATTED|EXTENDED|DEPENDENCY|AUTHORIZATION] hql_query
上面的执行语句中,有4个可选的关键字,其具体含义如下:
- FORMATTED:对执行计划进行格式化,返回JSON格式的执行计划
- EXTENDED:提供一些额外的信息,比如文件的路径信息
- DEPENDENCY:以JSON格式返回查询所依赖的表和分区的列表,从Hive0.10开始使用,如下图
- AUTHORIZATION:列出需要被授权的条目,包括输入与输出,从Hive0.14开始使用,如下图
一个典型的查询执行计划主要包括三部分,具体如下:
- Abstract Syntax Tree (AST):抽象语法树,Hive使用一个称之为antlr的解析生成器,可以自动地将HQL生成为抽象语法树
- Stage Dependencies:会列出运行查询所有的依赖以及stage的数量
- Stage Plans:包含了非常重要的信息,比如运行作业时的operator 和sort orders
举个栗子
假设有一张表:
CREATE TABLE employee_partitioned
(
name string,
work_place ARRAY<string>,
gender_age STRUCT<gender:string,age:int>,
skills_score MAP<string,int>,
depart_title MAP<STRING,ARRAY<STRING>>
)
PARTITIONED BY (Year INT, Month INT)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '|'
COLLECTION ITEMS TERMINATED BY ','
MAP KEYS TERMINATED BY ':';
查看执行计划:
EXPLAIN
SELECT gender_age.gender,
count(*)
FROM employee_partitioned
WHERE YEAR=2020
GROUP BY gender_age.gender
LIMIT 2;
执行计划概览:
如上图:Map/Reduce operator tree是抽象语法树AST部分;STAGE
DEPENDENCIES包括三个阶段:Stage-0 、Stage-1及Stage-2,其中Stage-0 是root stage,即Stage-1与Stage-2依赖于Stage-0;STAGE PLANS部分,Stage-1与Stage2都包含一个Map Operator Tree和一个Reduce Operator Tree,Stage-0不包含map和reduce,仅仅是一个fetch数据的操作。
执行计划详细信息:
STAGE DEPENDENCIES:
Stage-1 is a root stage
Stage-2 depends on stages: Stage-1
Stage-0 depends on stages: Stage-2
STAGE PLANS:
Stage: Stage-1
Map Reduce
Map Operator Tree:
TableScan
alias: employee_partitioned
filterExpr: (year = 2020) (type: boolean)
Statistics: Num rows: 1 Data size: 227 Basic stats: PARTIAL Column stats: NONE
Select Operator
expressions: gender_age (type: struct<gender:string,age:int>)
outputColumnNames: gender_age
Statistics: Num rows: 1 Data size: 227 Basic stats: PARTIAL Column stats: NONE
Reduce Output Operator
key expressions: gender_age.gender (type: string)
sort order: +
Map-reduce partition columns: rand() (type: double)
Statistics: Num rows: 1 Data size: 227 Basic stats: PARTIAL Column stats: NONE
Reduce Operator Tree:
Group By Operator
aggregations: count()
keys: KEY._col0 (type: string)
mode: partial1
outputColumnNames: _col0, _col1
Statistics: Num rows: 1 Data size: 227 Basic stats: COMPLETE Column stats: NONE
File Output Operator
compressed: false
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazybinary.LazyBinarySerDe
Stage: Stage-2
Map Reduce
Map Operator Tree:
TableScan
Reduce Output Operator
key expressions: _col0 (type: string)
sort order: +
Map-reduce partition columns: _col0 (type: string)
Statistics: Num rows: 1 Data size: 227 Basic stats: COMPLETE Column stats: NONE
value expressions: _col1 (type: bigint)
Reduce Operator Tree:
Group By Operator
aggregations: count(VALUE._col0)
keys: KEY._col0 (type: string)
mode: final
outputColumnNames: _col0, _col1