面試|不可不知的十大Hive調優技巧最佳實踐

Apache Hive是創建在Apache Hadoop之上的數據倉庫軟件項目,用於提供數據查詢和分析。Hive是Hadoop在HDFS上的SQL接口,它提供了相似於SQL的接口來查詢存儲在與Hadoop集成的各類數據庫和文件系統中的數據。能夠說從事數據開發工做,不管是在平時的工做中,仍是在面試中,Hive具備舉足輕重的地位,尤爲是Hive的性能調優方面,不只可以在工做中提高效率並且還能夠在面試中脫穎而出。在本文中,我將分享十個性能優化技術,全文以下。web

1.屢次INSERT單次掃描表

默認狀況下,Hive會執行屢次表掃描。所以,若是要在某張hive表中執行多個操做,建議使用一次掃描並使用該掃描來執行多個操做。面試

好比將一張表的數據屢次查詢出來裝載到另一張表中。以下面的示例,表my_table是一個分區表,分區字段爲dt,若是須要在表中查詢2個特定的分區日期數據,並將記錄裝載到2個不一樣的表中。數據庫

INSERT INTO temp_table_20201115 SELECT * FROM my_table WHERE dt ='2020-11-15';
INSERT INTO temp_table_20201116 SELECT * FROM my_table WHERE dt ='2020-11-16';

在以上查詢中,Hive將掃描表2次,爲了不這種狀況,咱們可使用下面的方式:apache

FROM my_table
INSERT INTO temp_table_20201115 SELECT * WHERE dt ='2020-11-15'
INSERT INTO temp_table_20201116 SELECT * WHERE dt ='2020-11-16'

這樣能夠確保只對my_table表執行一次掃描,從而能夠大大減小執行的時間和資源。緩存

2.分區表

對於一張比較大的表,將其設計成分區表能夠提高查詢的性能,對於一個特定分區的查詢,只會加載對應分區路徑的文件數據,所以,當用戶使用特定分區列值執行選擇查詢時,將僅針對該特定分區執行查詢,因爲將針對較少的數據量進行掃描,因此能夠提供更好的性能。值得注意的是,分區字段的選擇是影響查詢性能的重要因素,儘可能避免層級較深的分區,這樣會形成太多的子文件夾。性能優化

如今問題來了,該使用哪些列進行分區呢?一條基本的法則是:選擇低基數屬性做爲「分區鍵」,好比「地區」或「日期」等。微信

一些常見的分區字段能夠是:數據結構

  • 日期或者時間

好比year、month、day或者hour,當表中存在時間或者日期字段時,可使用些字段。app

  • 地理位置

好比國家、省份、城市等編輯器

  • 業務邏輯

好比部門、銷售區域、客戶等等

CREATE TABLE table_name (
    col1 data_type,
    col2 data_type)
PARTITIONED BY (partition1 data_type, partition2 data_type,….);

3.分桶表

一般,當很難在列上建立分區時,咱們會使用分桶,好比某個常常被篩選的字段,若是將其做爲分區字段,會形成大量的分區。在Hive中,會對分桶字段進行哈希,從而提供了中額外的數據結構,進行提高查詢效率。

與分區表相似,分桶表的組織方式是將HDFS上的文件分割成多個文件。分桶能夠加快數據採樣,也能夠提高join的性能(join的字段是分桶字段),由於分桶能夠確保某個key對應的數據在一個特定的桶內(文件),因此巧妙地選擇分桶字段能夠大幅度提高join的性能。一般狀況下,分桶字段能夠選擇常常用在過濾操做或者join操做的字段。

咱們可使用set.hive.enforce.bucketing = true啓用分桶設置。

當使用分桶表時,最好將bucketmapjoin標誌設置爲true,具體配置參數爲:

SET hive.optimize.bucketmapjoin = true

CREATE TABLE table_name 
PARTITIONED BY (partition1 data_type, partition2 data_type,….) CLUSTERED BY (column_name1, column_name2, …) 
SORTED BY (column_name [ASC|DESC], …)] 
INTO num_buckets BUCKETS;

4.對中間數據啓用壓縮

複雜的Hive查詢一般會轉換爲一系列多階段的MapReduce做業,而且這些做業將由Hive引擎連接起來以完成整個查詢。所以,此處的「中間輸出」是指上一個MapReduce做業的輸出,它將用做下一個MapReduce做業的輸入數據。

壓縮能夠顯著減小中間數據量,從而在內部減小了Map和Reduce之間的數據傳輸量。

咱們可使用如下屬性在中間輸出上啓用壓縮。

set hive.exec.compress.intermediate=true;
set hive.intermediate.compression.codec=org.apache.hadoop.io.compress.SnappyCodec;
set hive.intermediate.compression.type=BLOCK;

爲了將最終輸出到HDFS的數據進行壓縮,可使用如下屬性:

set hive.exec.compress.output=true;

下面是一些可使用的壓縮編解碼器

org.apache.hadoop.io.compress.DefaultCodec
org.apache.hadoop.io.compress.GzipCodec
org.apache.hadoop.io.compress.BZip2Codec
com.hadoop.compression.lzo.LzopCodec
org.apache.hadoop.io.compress.Lz4Codec
org.apache.hadoop.io.compress.SnappyCodec

5.Map端JOIN

map端join適用於當一張表很小(能夠存在內存中)的狀況,便可以將小表加載至內存。Hive從0.7開始支持自動轉爲map端join,具體配置以下:

SET hive.auto.convert.join=true; --  hivev0.11.0以後默認true
SET hive.mapjoin.smalltable.filesize=600000000; -- 默認 25m
SET hive.auto.convert.join.noconditionaltask=true; -- 默認true,因此不須要指定map join hint
SET hive.auto.convert.join.noconditionaltask.size=10000000; -- 控制加載到內存的表的大小

一旦開啓map端join配置,Hive會自動檢查小表是否大於hive.mapjoin.smalltable.filesize配置的大小,若是大於則轉爲普通的join,若是小於則轉爲map端join。

關於map端join的原理,以下圖所示:

首先,Task A(客戶端本地執行的task)負責讀取小表a,並將其轉成一個HashTable的數據結構,寫入到本地文件,以後將其加載至分佈式緩存。

而後,Task B任務會啓動map任務讀取大表b,在Map階段,根據每條記錄與分佈式緩存中的a表對應的hashtable關聯,並輸出結果

注意:map端join沒有reduce任務,因此map直接輸出結果,即有多少個map任務就會產生多少個結果文件。

6.向量化

Hive中的向量化查詢執行大大減小了典型查詢操做(如掃描,過濾器,聚合和鏈接)的CPU使用率。

標準查詢執行系統一次處理一行,在處理下一行以前,單行數據會被查詢中的全部運算符進行處理,致使CPU使用效率很是低。在向量化查詢執行中,數據行被批處理在一塊兒(默認=> 1024行),表示爲一組列向量。

要使用向量化查詢執行,必須以ORC格式(CDH 5)存儲數據,並設置如下變量。

SET hive.vectorized.execution.enabled=true

在CDH 6中默認啓用Hive查詢向量化,啓用查詢向量化後,還能夠設置其餘屬性來調整查詢向量化的方式,具體能夠參考cloudera官網。

7.謂詞下推

默認生成的執行計劃會在可見的位置執行過濾器,但在某些狀況下,某些過濾器表達式能夠被推到更接近首次看到此特定數據的運算符的位置。

好比下面的查詢:

select
    a.*,
    b.* 
from 
    a join b on (a.col1 = b.col1)
where a.col1 > 15 and b.col2 > 16

若是沒有謂詞下推,則在完成JOIN處理以後將執行過濾條件**(a.col1> 15和b.col2> 16)**。所以,在這種狀況下,JOIN將首先發生,而且可能產生更多的行,而後在進行過濾操做。

使用謂詞下推,這兩個謂詞**(a.col1> 15和b.col2> 16)**將在JOIN以前被處理,所以它可能會從a和b中過濾掉鏈接中較早處理的大部分數據行,所以,建議啓用謂詞下推。

經過將hive.optimize.ppd設置爲true能夠啓用謂詞下推。

SET hive.optimize.ppd=true

8.輸入格式選擇

Hive支持TEXTFILE, SEQUENCEFILE, AVRO, RCFILE, ORC,以及PARQUET文件格式,能夠經過兩種方式指定表的文件格式:

  • CREATE TABLE … STORE AS :即在建表時指定文件格式,默認是TEXTFILE
  • ALTER TABLE … [PARTITION partition_spec] SET FILEFORMAT :修改具體表的文件格式

若是未指定文件存儲格式,則默認使用的是參數hive.default.fileformat設定的格式。

若是數據存儲在小於塊大小的小文件中,則可使用SEQUENCE文件格式。若是要以減小存儲空間並提升性能的優化方式存儲數據,則可使用ORC文件格式,而當列中嵌套的數據過多時,Parquet格式會頗有用。所以,須要根據擁有的數據肯定輸入文件格式。

9.啓動嚴格模式

若是要查詢分區的Hive表,但不提供分區謂詞(分區列條件),則在這種狀況下,將針對該表的全部分區發出查詢,這可能會很是耗時且佔用資源。所以,咱們將下面的屬性定義爲strict,以指示在分區表上未提供分區謂詞的狀況下編譯器將引起錯誤。

SET hive.partition.pruning=strict

10.基於成本的優化

Hive在提交最終執行以前會優化每一個查詢的邏輯和物理執行計劃。基於成本的優化會根據查詢成本進行進一步的優化,從而可能產生不一樣的決策:好比如何決定JOIN的順序,執行哪一種類型的JOIN以及並行度等。

能夠經過設置如下參數來啓用基於成本的優化。

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;

可使用統計信息來優化查詢以提升性能。基於成本的優化器(CBO)還使用統計信息來比較查詢計劃並選擇最佳計劃。經過查看統計信息而不是運行查詢,效率會很高。

收集表的列統計信息:

ANALYZE TABLE mytable COMPUTE STATISTICS FOR COLUMNS;

查看my_db數據庫中my_table中my_id列的列統計信息:

DESCRIBE FORMATTED my_db.my_table my_id

結論

本文主要分享了10個Hive優化的基本技巧,但願可以爲你優化Hive查詢提供一個基本的思路。再次感謝你的閱讀,但願本文對你有所幫助。

本文分享自微信公衆號 - 浪尖聊大數據(bigdatatip)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索