(官方文檔翻譯整理及總結)
一、優化數據倉庫
① Hive LLAP 是一項接近實時結果查詢的技術,可用於BI工具以及網絡看板的應用,能夠將數據倉庫的查詢時間縮短到15秒之內,這樣的查詢稱之為Interactive Query。
Ambari安裝好之后,還需要額外的兩個步驟來開啟Hive LLAP:
1.在yarn中開啟Hive LLAP的優先使用權
2.打開hive中的Interactive Query開發並配置相關參數
② HiveServer2 高效的連接管理,類似於mysql連接池,在Ambari中配置好相關參數。
③ Tez Hive和MapReduce之間的中間層,對查詢進行預處理,對中間結果進行緩存。Tez ApplicationMaster 決定查詢的最大並發數。
二、使用ORCFile Format
原數據 csv格式(通用格式,一般從mysql導出這種格式的數據)
- 更小的空間占用
- 更快的查詢
先后對4種格式的表進行統計查詢,去重統計查詢,連接加去重查詢,詳細結果見截圖,可以得出結論,綜合存儲和查詢兩方面,orc file format都有較好的表現, 這也是HDP平台官方推薦的做法(parquet是CDH平台推薦的一種存儲格式)。
- 如何使用ORC格式 語法STORED AS orc
我們的數據,不論是從網絡爬取的還是從mysql導出的,一般都是csv格式的文本文件(也就是行和列的文本格式,一般指定‘\t’為列分隔符,‘\n’為行分隔符),先 創建一個textfile格式的hive表:
CREATE TABLE ...... ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘\t’ STORED AS TEXTFILE;
然后將文件中的數據一次性load進hive表:
LOAD DATA LOCAL INPATH ‘<path>’ OVERWRITE INTO TABLE ..;
接着CREATE TABLE new_table STORED AS orc AS SELECT * FROM old_table;復制一個orcfile格式的hive表,再刪掉舊表即可;
三、設計表結構時使用Partitions和Buckets
- CREATE TABLE sale(id int,amount decimal) PARTITIONED BY (date string)
創建表的時候指定一列或者多列來partition.常用的場景是按照日期來做partition,每天導入到Hive表中的都指定對應的partition,比如說:
INSERT INTO sale (date=”2017-9-12”) ... 這樣這一天的所有數據在HDFS中都會保存到表目錄下的名為2017-9-12的文件夾下。
這樣在查詢中只要涉及到日期這個字段都能大幅度提高查詢性能,因為執行過濾的時候只需要去掃描partition文件夾,而不需要使用MapReduce掃描整個表來進行 過濾。
Partition使用起來較為方便,但是有幾個需要注意的點:
1.絕不要對值唯一的列進行partition
2.規范好每一個partition的大小,最好大於1G
3.每一個查詢語句不要處理超過100的partitions
- Bucket是對表的進一步細分,在HDFS中是Partition文件夾下面的文件,
一個Bucket對應一個文件。如果Hive表的容量變化比較頻繁的話,不建議使用Bucket,因為需要動態的調整分桶,調整一些參數,不熟悉的話很容易引起性能問 題。Bucket典型的用法是用作隨機取樣,select語句后面跟:
TABLESAMPLING (BUCKET x OUT OF y)
四、優化查詢語句
Hive主要是數據分析引擎,query語句是大部分使用場景,所以對查詢語句的優化是非常有必要的。優化查詢首先還是要保證兩點:第一是保證語句先提交給Tez,而不是直接使用MapReduce,第二應該確認LLAP引擎正常運作。
接下來就要開始查詢語句的優化了,我們知道查詢語句最終還是會變成MapReduce任務來最終獲取需要的結果,所以查詢語句的優化本質上是MapReduce的優化,目的是為了MapReduce執行得更加有效率。
① 針對查詢語句的配置修改
- 矢量化查詢能夠提升掃描,聚合,過濾和連接操作的性能,開啟相關參數即可:
set hive.vectorized.execution.enabled = true;
set hive.vectorized.execution.reduce.enabled = true;
- 在Map端進行聚合操作:
set hive.map.aggr =true;
- 開啟Hive的並行化執行:set hive.exec.parallel = true
- 出現group by 操作在reduce階段耗費很長的時間,這種現象是由於數據傾斜造成的,也就是大部分數據都落到了同一個reducer上,在這種情況下需要配置:
set hive.tez.auto.reducer.parallelism=true ;
set hive.groupby.skewindata=true ;
set hive.optimize.skewjoin=true;
(其他時候不要這樣設置,因為這樣設置會增加reducer數量)
② 查詢語句的改寫
可以使用Hive View的工具對查詢語句進行圖形化的解釋(Visual Explain),通過解釋可以了解執行相關查詢語句的時候會執行哪些操作步驟以及每個步驟涉及到的行數等詳細信息。通過這些信息,我們可以直接比較查詢語句的不同寫法能夠帶來什么樣的優化效果。比如說有group by子句和沒有group by子句的兩種不同寫法的圖形化解釋,見下面例子,一個count功能的兩種寫法:
區別在於是否有group by子句,可以使用圖形化工具解釋兩句的查詢過程(從右至左):
- 多表連接查詢的時候,按照JOIN順序中的最后一個表應該盡量是大表,因為JOIN前一階段生成的數據會存在於Reducer的buffer中,通過stream最后面的表,直接從Reducer的buffer中讀取已經緩沖的中間結果數據(這個中間結果數據可能是JOIN順序中,前面表連接的結果的Key,數據量相對較小,內存開銷就小),這樣,與后面的大表進行連接時,只需要從buffer中讀取緩存的Key,與大表中的指定Key進行連接,速度會更快,也可能避免內存緩沖區溢出。目前版本的Hive可以開啟自動優化功能:
set hive.auto.convert.join = true
設置后,Hive會自動進行表連接的優化。但是對於一些比較復雜的多表查詢, 需要在查詢語句中隱式的手動聲明順序。例如:
SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val
FROM a
JOIN b ON (a.key = b.key1)
JOIN c ON (c.key = b.key1);
a表被視為大表。
SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a
JOIN b ON a.key = b.key;
MAPJION會把小表全部讀入內存中
- 改寫where子句。對於一些特殊的表連接查詢時,有時候可以把過濾條件放到on 子句里面。比如:
SELECT a.val, b.val
FROM a
LEFT OUTER JOIN b ON (a.key=b.key)
WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'
改寫:
SELECT a.val, b.val
FROM a
LEFT OUTER JOIN b
ON (a.key=b.key AND b.ds='2009-07-07' AND a.ds='2009-07-07')
改寫效果如圖:
首先完成2表JOIN,然后再通過WHERE條件進行過濾,這樣在JOIN過程中可能會輸出大量結果,再對這些結果進行過濾,比較耗時。可以進行優化,將WHERE 條件放在ON后,在JOIN的過程中,就對不滿足條件的記錄進行了預先過濾。
五、使用CBO組件
對查詢語句的修改優化需要不斷的實踐,同時需要對MapReduce的過程和各種操作有一定的了解。針對這種情況,Hive提供了一個工具:CBO()Cost-Based Optimizer.CBO是Hive查詢引擎的核心組件,它能夠優化和計算單個查詢各個計划(即操作流程)的消耗。然后在內部對查詢計划做一系列的優化和重寫,最后會生成Tez上的jobs,在hadoop上最終執行獲得結果。
CBO類似於一種靜態代碼檢測工具,所以為了讓CBO生效,需要事先讓Hive分析對應的表。開啟對列和表的靜態分析:
Purpose |
Command |
對沒有partitioned的表開啟靜態分析 |
ANALYZE TABLE [ |
對partitioned的表開啟靜態分析 |
ANALYZE TABLE [ |
對列開啟靜態分析 |
ANALYZE TABLE [ |
|
|