如何提高Hive 的查询性能?
Apache Hive是一种强大的数据分析工具。在处理数PB的数据时,了解如何提高查询性能非常重要。以下内容是基于 HDP-2.6.4 版本汇总的,如有不足之处,望指出。
1、使用Tez引擎
Apache Tez Engine是一个可扩展的框架,用于构建高性能批处理和交互式数据处理。它由YARN在Hadoop中 调度。Tez通过提高处理速度和保持MapReduce扩展到数PB数据的能力来改进MapReduce job。
通过设置hive.execution.engine 为tez:可以在环境中启用Tez引擎:
set hive.execution.engine=tez;
2、使用向量化
向量化通过在单个操作中获取 1024 行而不是 每次只获取单行来改善 scans, aggregations, filters 和 join 这类操作的性能。
我们可以通过执行以下命令在环境中启用向量化:
set hive.vectorized.execution.enabled=true;
set hive.vectorized.execution.reduce.enabled=true;
3、使用ORCFile
- Hive 支持 ORCfile,这是一种新的表存储格式,在读取,写入和处理数据时,ORCFile格式优于Hive文件格式,它通过 predicate push-down, compression 等技术来提高查询速度。
- 在 HIVE 表中使用 ORCFile,将有益于获得 HIVE 快速响应的查询。
- ORCFile 格式通过对原始数据存储量压缩75%,提供了高效的存储 Hive 数据的方法。
举例,考虑两个大表 A 和 B(存储为 TextFIle,这里没有指定一些列),使用一个简单的查询,如:
SELECT A.customerID,
A.name,
A.age,
A.address
JOIN B.role,
B.department,
B.salary ON A.customerID=B.customerID;
由于表 A 和表 B 都存储为 TextFile,因此执行此查询可能需要很长时间。
将这些表存储格式转换为 ORCFile 格式通常会明显减少查询时间:
CREATE TABLE A_ORC (
customerID int,
name string,
age int,
address string
) STORED AS ORC tblproperties (“orc.compress" = “SNAPPY”)
;
INSERT INTO TABLE A_ORC
SELECT *
FROM A
;
CREATE TABLE B_ORC (
customerID int,
ROLE string,
salary float,
department string
) STORED AS ORC tblproperties (“orc.compress" = “SNAPPY”)
;
INSERT INTO TABLE B_ORC
SELECT *
FROM B
;
SELECT A_ORC.customerID,
A_ORC.name,
A_ORC.age,
A_ORC.address
JOIN B_ORC.role,
B_ORC.department,
B_ORC.salary ON A_ORC.customerID=B_ORC.customerID
;
ORC 支持压缩存储(使用 ZLIB 或如上所示使用 SNAPPY),但也支持不压缩存储。
4、使用分区
通过分区,数据存储在 HDFS 上的单独单个文件夹中。Hive 将查询分区数据集,而不是 扫描表的所有数据集。
创建临时表并将数据加载到临时表中
CREATE TABLE Employee_Temp(
EmloyeeID int,
EmployeeName Varchar(100),
Address Varchar(100),
STATE Varchar(100),
City Varchar(100),
Zipcode Varchar(100)
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' STORED AS TEXTFILE;
LOAD DATA INPATH '/home/hadoop/hive' INTO TABLE Employee_Temp;
创建分区表
Create Table Employee_Part(
EmloyeeID int,
EmployeeName Varchar(100),
Address Varchar(100),
State Varchar(100),
Zipcode Varchar(100))
PARTITIONED BY (City Varchar(100))
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
启用动态分区的命令
SET hive.exec.dynamic.partition = true;
SET hive.exec.dynamic.partition.mode = nonstrict;
从临时表导入数据到分区表
INSERT Overwrite TABLE Employee_Part Partition(City)
SELECT EmployeeID,
EmployeeName,
Address,
STATE,
City,
Zipcode
FROM Emloyee_Temp;
5、使用 分桶
桶表介绍:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL+BucketedTables
举例:https://blog.csdn.net/m0_37534613/article/details/55258928
Hive 表被划分为多个分区,称为 Hive分区。Hive分区进一步细分为集群或桶,称为 bucket 或 Cluster。
Create Table Employee_Part(
EmloyeeID int,
EmployeeName Varchar(100),
Address Varchar(100),
State Varchar(100),
Zipcode Varchar(100))
PARTITIONED BY (City Varchar(100))
Clustered By (EmployeeID) into 20 Buckets
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
6、CBO 查询优化器
Hive CBO 是使用 Apache calcite 来处理的。
- 早期的 Hive 版本中(Hive-0.14 之前),在提交最终执行之前,Hive 会优化每个查询的逻辑和物理执行计划。 这些优化不是基于查询的成本优化(Cost-based Optimizer) 。
- 直到 Hive-0.14 时才添加了 Cost-based optimization ,这时已经根据查询的成本进行优化(例如要执行的连接类型,如何排序连接,并行度等)。
要使用基于成本的优化,需要在查询开头设置以下参数
set hive.cbo.enable=true;
set hive.compute.query.using.stats=true;
set hive.stats.fetch.column.stats=true;
set hive.stats.fetch.partition.stats=true;
如果要收集表信息,请使用 Analyze 命令。
7、写好的 SQL
SQL是一种强大的声明性语言。 与其他声明性语言一样,编写SQL语句的方法不止一种。
尽管每个语句的功能都相同,但它可能具有截然不同的性能特征。
我们来看一个例子。 考虑点击流事件表:
CREATE TABLE clicks (
timestamp date, sessionID string, url string, source_ip string
) STORED as ORC tblproperties (“orc.compress” = “SNAPPY”);
每条记录代表一次点击事件,我们希望找到每个sessionID的最新网址。
有人可能会考虑以下方法:
SELECT clicks.* FROM clicks inner join
(select sessionID, max(timestamp) as max_ts from clicks
group by sessionID) latest
ON clicks.sessionID = latest.sessionID and
clicks.timestamp = latest.max_ts;
在上面的查询中,我们构建一个子查询来收集每个会话中最新事件的时间戳,然后使用 内联接 来过滤掉其余的事件。
虽然查询是一个合理的解决方案, 但是从功能的角度来看 ,有一种更好的方法来重写这个查询,如下所示:
SELECT * FROM
(SELECT *, RANK() over (partition by sessionID,
order by timestamp desc) as rank
FROM clicks) ranked_clicks
WHERE ranked_clicks.rank=1;
在这里,我们使用 Hive 的 OLAP 窗口功能(OVER 和 RANK)来实现相同的功能。
显然,删除不必要的连接几乎总能带来更好的性能,而且当使用大数据时,这比以往任何时候都更重要。
我发现很多情况下查询不是最优的 – 所以仔细查看每个查询并考虑重写是否可以使它更好更快。
小结
Apache Hive是一个非常强大的数据分析工具,它支持批处理和交互式数据处理。
它是数据分析师和数据科学家最常用的技术之一。 在处理数PB的数据时,了解如何提高查询性能非常重要。以上汇总仅供参考!
参考
- https://cwiki.apache.org/confluence/display/Hive/StatsDev
- https://zh.hortonworks.com/blog/5-ways-make-hive-queries-run-faster/
- https://dzone.com/articles/how-to-improve-hive-query-performance-with-hadoop
- https://cwiki.apache.org/confluence/display/Hive/LanguageManual+WindowingAndAnalytics