如何提高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