數(shù)倉|Hive性能調(diào)優(yōu)指北

在企業(yè)中使用Hive構(gòu)建離線數(shù)倉是一種十分普遍的方案赏壹。盡管Hive的使用場景是通過批處理的方式處理大數(shù)據(jù),通常對處理時(shí)間不敏感七兜。但是在資源有限的情況下,我們需要關(guān)注Hive的性能調(diào)優(yōu)枯冈,從而方便數(shù)據(jù)的快速產(chǎn)出。同時(shí)办悟,關(guān)于Hive的性能調(diào)優(yōu)尘奏,也是面試中比較常見的問題,因此掌握Hive性能調(diào)優(yōu)的一些方法病蛉,不僅能夠在工作中提升效率而且還可以在面試中脫穎而出炫加。本文會(huì)通過四個(gè)方面介紹Hive性能調(diào)優(yōu),主要包括:

  • 性能調(diào)優(yōu)的工具

  • 設(shè)計(jì)優(yōu)化

  • 數(shù)據(jù)存儲(chǔ)優(yōu)化

  • 作業(yè)優(yōu)化

性能調(diào)優(yōu)的工具

HQL提供了兩個(gè)查看查詢性能的工具:explainanalyze铺然,除此之外Hive的日志也提供了非常詳細(xì)的信息琢感,方便查看執(zhí)行性能和報(bào)錯(cuò)排查。

善用explain語句

explain語句是查看執(zhí)行計(jì)劃經(jīng)常使用的一個(gè)工具探熔,可以使用該語句分析查詢執(zhí)行計(jì)劃,具體使用語法如下:

EXPLAIN [FORMATTED|EXTENDED|DEPENDENCY|AUTHORIZATION] hql_query

上面的執(zhí)行語句中烘挫,有4個(gè)可選的關(guān)鍵字诀艰,其具體含義如下:

  • FORMATTED:對執(zhí)行計(jì)劃進(jìn)行格式化,返回JSON格式的執(zhí)行計(jì)劃
  • EXTENDED:提供一些額外的信息饮六,比如文件的路徑信息
  • DEPENDENCY:以JSON格式返回查詢所依賴的表和分區(qū)的列表其垄,從Hive0.10開始使用,如下圖
  • AUTHORIZATION:列出需要被授權(quán)的條目卤橄,包括輸入與輸出绿满,從Hive0.14開始使用,如下圖

一個(gè)典型的查詢執(zhí)行計(jì)劃主要包括三部分,具體如下:

  • Abstract Syntax Tree (AST):抽象語法樹窟扑,Hive使用一個(gè)稱之為antlr的解析生成器喇颁,可以自動(dòng)地將HQL生成為抽象語法樹
  • Stage Dependencies:會(huì)列出運(yùn)行查詢所有的依賴以及stage的數(shù)量
  • Stage Plans:包含了非常重要的信息,比如運(yùn)行作業(yè)時(shí)的operator 和sort orders

舉個(gè)栗子

假設(shè)有一張表:

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 ':';

查看執(zhí)行計(jì)劃:

EXPLAIN
SELECT gender_age.gender,
       count(*)
FROM employee_partitioned
WHERE YEAR=2020
GROUP BY gender_age.gender
LIMIT 2;

執(zhí)行計(jì)劃概覽:

如上圖:Map/Reduce operator tree是抽象語法樹AST部分嚎货;STAGE
DEPENDENCIES
包括三個(gè)階段:Stage-0 橘霎、Stage-1及Stage-2,其中Stage-0 是root stage殖属,即Stage-1與Stage-2依賴于Stage-0姐叁;STAGE PLANS部分,Stage-1與Stage2都包含一個(gè)Map Operator Tree和一個(gè)Reduce Operator Tree,Stage-0不包含map和reduce外潜,僅僅是一個(gè)fetch數(shù)據(jù)的操作原环。

執(zhí)行計(jì)劃詳細(xì)信息:

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
          Statistics: Num rows: 1 Data size: 227 Basic stats: COMPLETE Column stats: NONE
          Limit
            Number of rows: 2
            Statistics: Num rows: 1 Data size: 227 Basic stats: COMPLETE Column stats: NONE
            File Output Operator
              compressed: false
              Statistics: Num rows: 1 Data size: 227 Basic stats: COMPLETE Column stats: NONE
              table:
                  input format: org.apache.hadoop.mapred.TextInputFormat
                  output format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
                  serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe

  Stage: Stage-0
    Fetch Operator
      limit: 2
      Processor Tree:
        ListSink

巧用analyze語句

analyze語句可以收集一些詳細(xì)的統(tǒng)計(jì)信息,比如表的行數(shù)处窥、文件數(shù)嘱吗、數(shù)據(jù)的大小等信息。這些統(tǒng)計(jì)信息作為元數(shù)據(jù)存儲(chǔ)在hive的元數(shù)據(jù)庫中碧库。Hive支持表柜与、分區(qū)和列級別的統(tǒng)計(jì)(與Impala類似),這些信息作為Hive基于成本優(yōu)化策略(Cost-Based Optimizer (CBO))的輸入,該優(yōu)化器的主要作用是選擇耗費(fèi)最小系統(tǒng)資源的查詢計(jì)劃嵌灰。其實(shí)弄匕,在Hive3.2.0版本中,可以自動(dòng)收集這些統(tǒng)計(jì)信息沽瞭,當(dāng)然也可以通過analyze語句進(jìn)行手動(dòng)統(tǒng)計(jì)表迁匠、分區(qū)或者字段的信息。具體的使用方式如下:

  • 1.收集表的統(tǒng)計(jì)信息(非分區(qū)表)驹溃,當(dāng)指定NOSCAN關(guān)鍵字時(shí)城丧,會(huì)忽略掃描文件內(nèi)容,僅僅統(tǒng)計(jì)文件的數(shù)量與大小豌鹤,速度會(huì)比較快
-- 不使用NOSCAN關(guān)鍵字
hive> ANALYZE TABLE user_behavior  COMPUTE STATISTICS;
...
Table default.user_behavior stats: [numFiles=1, numRows=10, totalSize=229, rawDataSize=219]
Time taken: 23.504 seconds
-- 使用NOSCAN關(guān)鍵字
hive> ANALYZE TABLE user_behavior  COMPUTE STATISTICS NOSCAN;
Table default.user_behavior stats: [numFiles=1, numRows=10, totalSize=229, rawDataSize=219]
Time taken: 0.309 seconds
  • 2.收集分區(qū)表的統(tǒng)計(jì)信息
-- 收集具體分區(qū)的統(tǒng)計(jì)信息
hive> ANALYZE TABLE employee_partitioned PARTITION(year=2020, month=06) COMPUTE STATISTICS;
...
Partition default.employee_partitioned{year=2020, month=06} stats: [numFiles=1, numRows=0, totalSize=227, rawDataSize=0]
Time taken: 19.283 seconds

-- 收集所有分區(qū)的統(tǒng)計(jì)信息
hive> ANALYZE TABLE employee_partitioned PARTITION(year, month) COMPUTE STATISTICS;
...
Partition default.employee_partitioned{year=2020, month=06} stats: [numFiles=1, numRows=0, totalSize=227, rawDataSize=0]
Time taken: 17.528 seconds
  • 3.收集表的某個(gè)字段的統(tǒng)計(jì)信息
hive> ANALYZE TABLE user_behavior COMPUTE STATISTICS FOR COLUMNS user_id ; 

尖叫提示

可以通過設(shè)置:SET hive.stats.autogather=true亡哄,進(jìn)行自動(dòng)收集統(tǒng)計(jì)信息,對于INSERT OVERWRITE/INTO操作的表或者分區(qū)布疙,可以自動(dòng)收集統(tǒng)計(jì)信息蚊惯。值得注意的是,LOAD操作不能夠自動(dòng)收集統(tǒng)計(jì)信息

一旦這些統(tǒng)計(jì)信息收集完畢灵临,可以通過DESCRIBE EXTENDED/FORMATTED語句查詢統(tǒng)計(jì)信息截型,具體使用如下:

-- 查看一個(gè)分區(qū)的統(tǒng)計(jì)信息
hive> DESCRIBE FORMATTED employee_partitioned PARTITION(year=2020, month=06);
...
Partition Parameters:            
        COLUMN_STATS_ACCURATE   true                
        numFiles                1                   
        numRows                 0                   
        rawDataSize             0                   
        totalSize               227                 
        transient_lastDdlTime   1591437967 
...
-- 查看一張表的統(tǒng)計(jì)信息
hive> DESCRIBE FORMATTED employee_partitioned;
...
Table Parameters:                
        numPartitions           1                   
        transient_lastDdlTime   1591431482 
...
-- 查看某列的統(tǒng)計(jì)信息
hive> DESCRIBE FORMATTED  user_behavior.user_id;

常用日志分析

日志提供了job運(yùn)行的詳細(xì)信息,通過查看日志信息儒溉,可以分析出導(dǎo)致作業(yè)執(zhí)行瓶頸的問題宦焦,主要包括兩種類型的日志:系統(tǒng)日志和作業(yè)日志。

系統(tǒng)日志包含了Hive運(yùn)行時(shí)的狀態(tài)等信息顿涣,可以通過{HIVE_HOME}/conf/hive-log4j.properties文件進(jìn)行配置波闹,主要的配置選項(xiàng)有:

hive.root.logger=WARN,DRFA ## 日志級別
hive.log.dir=/tmp/${user.name} ## 日志路徑
hive.log.file=hive.log ## 日志名稱

也可以通過Hive cli命令行設(shè)置日志級別:$hive --hiveconf hive.root.logger=DEBUG,console這種方式只能在當(dāng)前會(huì)話生效。

作業(yè)日志所包含的作業(yè)信息通常是由YARN管理的涛碑,可以通過yarn logs -applicationId <application_id>命令查看作業(yè)日志舔痪。

設(shè)計(jì)優(yōu)化

分區(qū)表

對于一張比較大的表,將其設(shè)計(jì)成分區(qū)表可以提升查詢的性能锌唾,對于一個(gè)特定分區(qū)的查詢锄码,只會(huì)加載對應(yīng)分區(qū)路徑的文件數(shù)據(jù)夺英,所以執(zhí)行速度會(huì)比較快。值得注意的是滋捶,分區(qū)字段的選擇是影響查詢性能的重要因素痛悯,盡量避免層級較深的分區(qū),這樣會(huì)造成太多的子文件夾重窟。一些常見的分區(qū)字段可以是:

  • 日期或者時(shí)間

比如year载萌、month、day或者h(yuǎn)our巡扇,當(dāng)表中存在時(shí)間或者日期字段時(shí)扭仁,可以使用些字段。

  • 地理位置

比如國家厅翔、省份乖坠、城市等

  • 業(yè)務(wù)邏輯

比如部門、銷售區(qū)域刀闷、客戶等等

分桶表

與分區(qū)表類似熊泵,分桶表的組織方式是將HDFS上的文件分割成多個(gè)文件。分桶可以加快數(shù)據(jù)采樣甸昏,也可以提升join的性能(join的字段是分桶字段)顽分,因?yàn)榉滞翱梢源_保某個(gè)key對應(yīng)的數(shù)據(jù)在一個(gè)特定的桶內(nèi)(文件),所以巧妙地選擇分桶字段可以大幅度提升join的性能施蜜。通常情況下卒蘸,分桶字段可以選擇經(jīng)常用在過濾操作或者join操作的字段。

索引

創(chuàng)建索引是關(guān)系型數(shù)據(jù)庫性能調(diào)優(yōu)的常見手段翻默,在Hive中也不例外缸沃。Hive從0.7版本開始支持索引,使用索引相比全表掃描而言冰蘑,是一種比較廉價(jià)的操作,Hive中創(chuàng)建索引的方式如下:

CREATE INDEX idx_user_id_user_behavior
ON TABLE user_behavior (user_id)
AS 'COMPACT'
WITH DEFERRED REBUILD;

上面創(chuàng)建的是COMPACT索引村缸,存儲(chǔ)的是索引列與其對應(yīng)的block id的pair對祠肥。除了此種索引外,Hive還支持位圖索引(BITMAP),使用方式如下:

CREATE INDEX idx_behavior_user_behavior
ON TABLE user_behavior (behavior)
AS 'BITMAP'
WITH DEFERRED REBUILD;

上面創(chuàng)建的索引時(shí)梯皿,使用了WITH DEFERRED REBUILD選項(xiàng)仇箱,該選項(xiàng)可以避免索引立即被創(chuàng)建,當(dāng)建立索引時(shí)东羹,可以使用LTER...REBUILD命令(見下面的示例)剂桥,值得注意的是:當(dāng)基表(被創(chuàng)建索引的表)發(fā)生變化時(shí),該命令需要被再次執(zhí)行以便更新索引到最新的狀態(tài)属提。

ALTER INDEX idx_user_id_user_behavior ON user_behavior REBUILD;

一旦索引創(chuàng)建成功权逗,會(huì)生成一張索引表美尸,表的名稱格式為:數(shù)據(jù)庫名__表名_索引名__,可以使用下面的命令查看索引:

hive> SHOW TABLES '*idx*';
OK
default__user_behavior_idx_user_id_user_behavior__
Time taken: 0.044 seconds, Fetched: 1 row(s)

索引表包含索引列斟薇、HDFS的文件URI以及每行的偏移量师坎,可以通過下面命令查看:

-- 查看索引表結(jié)構(gòu)
hive> DESC default__user_behavior_idx_user_id_user_behavior__;
OK
user_id                 int                                         
_bucketname             string                                      
_offsets                array<bigint>                               
Time taken: 0.109 seconds, Fetched: 3 row(s)
-- 查看索引表內(nèi)容
hive> SELECT * FROM default__user_behavior_idx_user_id_user_behavior__;
OK
9       hdfs://cdh03:8020/user/hive/warehouse/user_behavior/userbehavior.csv    [181]
7       hdfs://cdh03:8020/user/hive/warehouse/user_behavior/userbehavior.csv    [136]
1       hdfs://cdh03:8020/user/hive/warehouse/user_behavior/userbehavior.csv    [0]
6       hdfs://cdh03:8020/user/hive/warehouse/user_behavior/userbehavior.csv    [113]
5       hdfs://cdh03:8020/user/hive/warehouse/user_behavior/userbehavior.csv    [90]
10      hdfs://cdh03:8020/user/hive/warehouse/user_behavior/userbehavior.csv    [205]
4       hdfs://cdh03:8020/user/hive/warehouse/user_behavior/userbehavior.csv    [66]
8       hdfs://cdh03:8020/user/hive/warehouse/user_behavior/userbehavior.csv    [158]
3       hdfs://cdh03:8020/user/hive/warehouse/user_behavior/userbehavior.csv    [44]
2       hdfs://cdh03:8020/user/hive/warehouse/user_behavior/userbehavior.csv    [22]
Time taken: 0.28 seconds, Fetched: 10 row(s)

如果要?jiǎng)h除索引,可以使用DROP INDEX命令堪滨,如下:

DROP INDEX idx_user_id_user_behavior ON user_behavior;

使用skewed/temporary表

Hive除了可以使用內(nèi)部表胯陋、外部表、分區(qū)表袱箱、分桶表之外遏乔,也可以使用skewed/temporary表,也可以在一定程度上提升性能发笔。

Hive從0.10版本之后開始支持skewed表盟萨,該表可以緩解數(shù)據(jù)傾斜。這種表之所以能夠提升性能筐咧,是因?yàn)榭梢宰詣?dòng)將造成數(shù)據(jù)傾斜的數(shù)據(jù)分割成不同的文件或者路徑鸯旁。使用示例如下:

CREATE TABLE sample_skewed_table (
dept_no int, 
dept_name string
) 
SKEWED BY (dept_no) ON (1000, 2000);-- 指定數(shù)據(jù)傾斜字段

另外,還可以使用temporary臨時(shí)表量蕊,將公共使用部分的數(shù)據(jù)集建成臨時(shí)表铺罢,同時(shí)臨時(shí)表支持SSD或memory的數(shù)據(jù)存儲(chǔ),從而可以提升性能残炮。

數(shù)據(jù)存儲(chǔ)優(yōu)化

文件格式

Hive支持TEXTFILE, SEQUENCEFILE, AVRO, RCFILE, ORC,以及PARQUET文件格式韭赘,可以通過兩種方式指定表的文件格式:

  • CREATE TABLE ... STORE AS <file_format>:即在建表時(shí)指定文件格式,默認(rèn)是TEXTFILE
  • ALTER TABLE ... [PARTITION partition_spec] SET FILEFORMAT <file_format>:修改具體表的文件格式

一旦存儲(chǔ)文件格式為TEXT的表被創(chuàng)建势就,可以直接通過load命令裝載一個(gè)text類型的文件泉瞻。我們可以先使用此命令將數(shù)據(jù)裝載到一張TEXT格式的表中,然后在通過INSERT OVERWRITE/INTO TABLE ... SELECT命令將數(shù)據(jù)裝載到其他文件格式的表中苞冯。

尖叫提示

如果要改變創(chuàng)建表的默認(rèn)文件格式袖牙,可以使用hive.default.fileformat=<file_format>進(jìn)行配置,改配置可以針對所有表舅锄。同時(shí)也可以使用hive.default.fileformat.managed =
<file_format>進(jìn)行配置鞭达,改配置僅適用于內(nèi)部表或外部表

TEXT, SEQUENCE和 AVRO文件是面向行的文件存儲(chǔ)格式,不是最佳的文件格式皇忿,因?yàn)榧幢闶侵徊樵円涣袛?shù)據(jù)畴蹭,使用這些存儲(chǔ)格式的表也需要讀取完整的一行數(shù)據(jù)。另一方面鳍烁,面向列的存儲(chǔ)格式(RCFILE, ORC, PARQUET)可以很好地解決上面的問題叨襟。關(guān)于每種文件格式的說明,如下:

  • TEXTFILE

創(chuàng)建表時(shí)的默認(rèn)文件格式幔荒,數(shù)據(jù)被存儲(chǔ)成文本格式糊闽。文本文件可以被分割和并行處理梳玫,也可以使用壓縮,比如GZip墓怀、LZO或者Snappy汽纠。然而大部分的壓縮文件不支持分割和并行處理,會(huì)造成一個(gè)作業(yè)只有一個(gè)mapper去處理數(shù)據(jù)傀履,使用壓縮的文本文件要確保文件的不要過大虱朵,一般接近兩個(gè)HDFS塊的大小。

  • SEQUENCEFILE

key/value對的二進(jìn)制存儲(chǔ)格式钓账,sequence文件的優(yōu)勢是比文本格式更好壓縮碴犬,sequence文件可以被壓縮成塊級別的記錄,塊級別的壓縮是一個(gè)很好的壓縮比例梆暮。如果使用塊壓縮服协,需要使用下面的配置:set hive.exec.compress.output=true; set io.seqfile.compression.type=BLOCK

  • AVRO

二進(jìn)制格式文件,除此之外啦粹,avro也是一個(gè)序列化和反序列化的框架偿荷。avro提供了具體的數(shù)據(jù)schema。

  • RCFILE

全稱是Record Columnar File唠椭,首先將表分為幾個(gè)行組跳纳,對每個(gè)行組內(nèi)的數(shù)據(jù)進(jìn)行按列存儲(chǔ),每一列的數(shù)據(jù)都是分開存儲(chǔ)贪嫂,即先水平劃分寺庄,再垂直劃分。

  • ORC

全稱是Optimized Row Columnar力崇,從hive0.11版本開始支持斗塘,ORC格式是RCFILE格式的一種優(yōu)化的格式,提供了更大的默認(rèn)塊(256M)

  • PARQUET

另外一種列式存儲(chǔ)的文件格式亮靴,與ORC非常類似馍盟,與ORC相比,Parquet格式支持的生態(tài)更廣茧吊,比如低版本的impala不支持orc格式

壓縮

壓縮技術(shù)可以減少map與reduce之間的數(shù)據(jù)傳輸贞岭,從而可以提升查詢性能,關(guān)于壓縮的配置可以在hive的命令行中或者h(yuǎn)ive-site.xml文件中進(jìn)行配置

SET hive.exec.compress.intermediate=true

開啟壓縮之后饱狂,可以選擇下面的壓縮格式:


關(guān)于壓縮的編碼器可以通過mapred-site.xml, hive-site.xml進(jìn)行配置曹步,也可以通過命令行進(jìn)行配置,比如:

-- 中間結(jié)果壓縮
SET hive.intermediate.compression.codec=org.apache.hadoop.io.compress.SnappyCodec
-- 輸出結(jié)果壓縮
SET hive.exec.compress.output=true;
SET mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodc

存儲(chǔ)優(yōu)化

經(jīng)常被訪問的數(shù)據(jù)稱之為熱數(shù)據(jù)宪彩,可以針對熱數(shù)據(jù)提升查詢的性能休讳。比如通過增加熱數(shù)據(jù)的副本數(shù),可以增加數(shù)據(jù)本地性命中的可能性尿孔,從而提升查詢性能俊柔,當(dāng)然這要與存儲(chǔ)容量之間做出權(quán)衡筹麸。

$ hdfs dfs -setrep -R -w 4 /user/hive/warehouse/employee

注意,大量的小文件或者冗余副本會(huì)造成namenode節(jié)點(diǎn)內(nèi)存耗費(fèi)雏婶,尤其是大量小于HDFS塊大小的文件物赶。HDSF本身提供了應(yīng)對小文件的解決方案:

  • Hadoop Archive/HAR:將小文件打包成大文件
  • SEQUENCEFILE格式:將小文件壓縮成大文件
  • CombineFileInputFormat:在map和reduce處理之前組合小文件
  • HDFS Federation:HDFS聯(lián)盟,使用多個(gè)namenode節(jié)點(diǎn)管理文件

對于Hive而言留晚,可以使用下面的配置將查詢結(jié)果的文件進(jìn)行合并酵紫,從而避免產(chǎn)生小文件:

  • hive.merge.mapfiles: 在一個(gè)僅有map的作業(yè)中,合并最后的結(jié)果文件错维,默認(rèn)為true
  • hive.merge.mapredfiles:合并mapreduce作業(yè)的結(jié)果小文件 默認(rèn)false奖地,可以設(shè)置true
  • hive.merge.size.per.task:定義合并文件的大小,默認(rèn) 256,000,000赋焕,即256MB
  • hive.merge.smallfiles.avgsize: T觸發(fā)文件合并的文件大小閾值参歹,默認(rèn)值是16,000,000

當(dāng)一個(gè)作業(yè)的輸出結(jié)果文件的大小小于hive.merge.smallfiles.avgsize設(shè)定的閾值,并且hive.merge.mapfiles與hive.merge.mapredfiles設(shè)置為true隆判,Hive會(huì)額外啟動(dòng)一個(gè)mr作業(yè)將輸出小文件合并成大文件犬庇。

作業(yè)優(yōu)化

本地模式

當(dāng)Hive處理的數(shù)據(jù)量較小時(shí),啟動(dòng)分布式去處理數(shù)據(jù)會(huì)有點(diǎn)浪費(fèi)侨嘀,因?yàn)榭赡軉?dòng)的時(shí)間比數(shù)據(jù)處理的時(shí)間還要長臭挽,從Hive0.7版本之后,Hive支持將作業(yè)動(dòng)態(tài)地轉(zhuǎn)為本地模式飒炎,需要使用下面的配置:

SET hive.exec.mode.local.auto=true; -- 默認(rèn) false
SET hive.exec.mode.local.auto.inputbytes.max=50000000;
SET hive.exec.mode.local.auto.input.files.max=5; -- 默認(rèn) 4

一個(gè)作業(yè)只要滿足下面的條件埋哟,會(huì)啟用本地模式

  • 輸入文件的大小小于hive.exec.mode.local.auto.inputbytes.max配置的大小
  • map任務(wù)的數(shù)量小于hive.exec.mode.local.auto.input.files.max配置的大小
  • reduce任務(wù)的數(shù)量是1或者0

JVM重用

默認(rèn)情況下,Hadoop會(huì)為為一個(gè)map或者reduce啟動(dòng)一個(gè)JVM郎汪,這樣可以并行執(zhí)行map和reduce赤赊。當(dāng)map或者reduce是那種僅運(yùn)行幾秒鐘的輕量級作業(yè)時(shí),JVM啟動(dòng)進(jìn)程所耗費(fèi)的時(shí)間會(huì)比作業(yè)執(zhí)行的時(shí)間還要長煞赢。Hadoop可以重用JVM抛计,通過共享JVM以串行而非并行的方式運(yùn)行map或者reduce。JVM的重用適用于同一個(gè)作業(yè)的map和reduce照筑,對于不同作業(yè)的task不能夠共享JVM吹截。如果要開啟JVM重用,需要配置一個(gè)作業(yè)最大task數(shù)量凝危,默認(rèn)值為1波俄,如果設(shè)置為-1,則表示不限制:

SET mapreduce.job.jvm.numtasks=5;

這個(gè)功能的缺點(diǎn)是蛾默,開啟JVM重用將一直占用使用到的task插槽懦铺,以便進(jìn)行重用,直到任務(wù)完成后才能釋放支鸡。如果某個(gè)“不平衡的”job中有某幾個(gè)reduce task執(zhí)行的時(shí)間要比其他Reduce task消耗的時(shí)間多的多的話冬念,那么保留的插槽就會(huì)一直空閑著卻無法被其他的job使用趁窃,直到所有的task都結(jié)束了才會(huì)釋放。

并行執(zhí)行

Hive的查詢通常會(huì)被轉(zhuǎn)換成一系列的stage急前,這些stage之間并不是一直相互依賴的醒陆,所以可以并行執(zhí)行這些stage,可以通過下面的方式進(jìn)行配置:

SET hive.exec.parallel=true; -- 默認(rèn)false
SET hive.exec.parallel.thread.number=16; -- 默認(rèn)8

并行執(zhí)行可以增加集群資源的利用率裆针,如果集群的資源使用率已經(jīng)很高了刨摩,那么并行執(zhí)行的效果不會(huì)很明顯。

Fetch模式

Fetch模式是指Hive中對某些情況的查詢可以不必使用MapReduce計(jì)算世吨÷肓冢可以簡單地讀取表對應(yīng)的存儲(chǔ)目錄下的文件,然后輸出查詢結(jié)果到控制臺另假。在開啟fetch模式之后像屋,在全局查找、字段查找边篮、limit查找等都啟動(dòng)mapreduce己莺,通過下面方式進(jìn)行配置:

hive.fetch.task.conversion=more

JOIN優(yōu)化

普通join

普通join又稱之為reduce端join,是一種最基本的join戈轿,并且耗時(shí)較長凌受。對于大表join小表,需要將大表放在右側(cè)思杯,即小表join大表胜蛉。新版的hive已經(jīng)對小表JOIN大表和大表JOIN小表進(jìn)行了優(yōu)化。小表放在左邊和右邊已經(jīng)沒有明顯區(qū)別色乾。

map端join

map端join適用于當(dāng)一張表很小(可以存在內(nèi)存中)的情況誊册,即可以將小表加載至內(nèi)存。Hive從0.7開始支持自動(dòng)轉(zhuǎn)為map端join暖璧,具體配置如下:

SET hive.auto.convert.join=true; --  hivev0.11.0之后默認(rèn)true
SET hive.mapjoin.smalltable.filesize=600000000; -- 默認(rèn) 25m
SET hive.auto.convert.join.noconditionaltask=true; -- 默認(rèn)true案怯,所以不需要指定map join hint
SET hive.auto.convert.join.noconditionaltask.size=10000000; -- 控制加載到內(nèi)存的表的大小

一旦開啟map端join配置,Hive會(huì)自動(dòng)檢查小表是否大于hive.mapjoin.smalltable.filesize配置的大小澎办,如果大于則轉(zhuǎn)為普通的join嘲碱,如果小于則轉(zhuǎn)為map端join。

關(guān)于map端join的原理局蚀,如下圖所示:

首先麦锯,Task A(客戶端本地執(zhí)行的task)負(fù)責(zé)讀取小表a,并將其轉(zhuǎn)成一個(gè)HashTable的數(shù)據(jù)結(jié)構(gòu)琅绅,寫入到本地文件扶欣,之后將其加載至分布式緩存。

然后,Task B任務(wù)會(huì)啟動(dòng)map任務(wù)讀取大表b宵蛀,在Map階段,根據(jù)每條記錄與分布式緩存中的a表對應(yīng)的hashtable關(guān)聯(lián)县貌,并輸出結(jié)果

注意:map端join沒有reduce任務(wù)术陶,所以map直接輸出結(jié)果,即有多少個(gè)map任務(wù)就會(huì)產(chǎn)生多少個(gè)結(jié)果文件煤痕。

Bucket map join

bucket map join是一種特殊的map端join梧宫,主要區(qū)別是其應(yīng)用在分桶表上。如果要開啟分桶的map端join摆碉,需要開啟一下配置:

SET hive.auto.convert.join=true;
SET hive.optimize.bucketmapjoin=true; -- 默認(rèn)false

在一個(gè)分桶的map端join中塘匣,所有參與join的表必須是分桶表,并且join的字段是分桶字段(通過CLUSTERED BY指定)巷帝,另外忌卤,對于大表的分桶數(shù)量必須是小表分桶數(shù)量的倍數(shù)。

與普通的join相比楞泼,分桶join僅僅只讀取所需要的桶數(shù)據(jù)驰徊,不需要全表掃描。

Sort merge bucket (SMB) join

SMBjoin應(yīng)用與分桶表堕阔,如果兩張參與join的表是排序的棍厂,并且分桶字段相同,這樣可以使用sort-merge join超陆,其優(yōu)勢在于不用把小表完全加載至內(nèi)存中牺弹,會(huì)讀取兩張分桶表對應(yīng)的桶,執(zhí)行普通join(包括map與reduce)配置如下:

SET hive.input.format=
org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
SET hive.auto.convert.sortmerge.join=true;
SET hive.optimize.bucketmapjoin=true;
SET hive.optimize.bucketmapjoin.sortedmerge=true;
SET hive.auto.convert.sortmerge.join.noconditionaltask=true;

Sort merge bucket map (SMBM) join

SMBM join是一種特殊的bucket map join时呀,與map端join不同的是张漂,不用將小表的所有數(shù)據(jù)行都加載至內(nèi)存中。使用SMBM join谨娜,參與join的表必須是排序的鹃锈,有著相同的分桶字段,并且join字段與分桶字段相同瞧预。配置如下:

SET hive.auto.convert.join=true;
SET hive.auto.convert.sortmerge.join=true
SET hive.optimize.bucketmapjoin=true;
SET hive.optimize.bucketmapjoin.sortedmerge=true;
SET hive.auto.convert.sortmerge.join.noconditionaltask=true;
SET hive.auto.convert.sortmerge.join.bigtable.selection.policy=
org.apache.hadoop.hive.ql.optimizer.TableSizeBasedBigTableSelectorForAutoSMJ;

Skew join

當(dāng)被處理的數(shù)據(jù)分布極其不均勻時(shí)屎债,會(huì)造成數(shù)據(jù)傾斜的現(xiàn)象。Hive可以通過如下的配置優(yōu)化數(shù)據(jù)傾斜的情況:

-- 默認(rèn)false垢油,如果數(shù)據(jù)傾斜盆驹,可以將其設(shè)置為true
SET hive.optimize.skewjoin=true;
-- 默認(rèn)為100000,如果key的數(shù)量大于配置的值滩愁,則超過的數(shù)量的key對應(yīng)的數(shù)據(jù)會(huì)被發(fā)送到其他的reduce任務(wù)
SET hive.skewjoin.key=100000;

尖叫提示

數(shù)據(jù)傾斜在group by的情況下也會(huì)發(fā)生躯喇,所以可以開啟一個(gè)配置:set hive.groupby.skewindata=true,優(yōu)化group by出現(xiàn)的數(shù)據(jù)傾斜,一旦開啟之后廉丽,執(zhí)行作業(yè)時(shí)會(huì)首先額外觸發(fā)一個(gè)mr作業(yè)倦微,該作業(yè)的map任務(wù)的輸出會(huì)被隨機(jī)地分配到reduce任務(wù)上,從而避免數(shù)據(jù)傾斜

執(zhí)行引擎

Hive支持多種執(zhí)行引擎正压,比如spark欣福、tez。對于執(zhí)行引擎的選擇焦履,會(huì)影響整體的查詢性能拓劝。使用的配置如下:

SET hive.execution.engine=<engine>; -- <engine> = mr|tez|spark
  • mr:默認(rèn)的執(zhí)行引擎,在Hive2.0版本版本中被標(biāo)記過時(shí)
  • tez:可以將多個(gè)有依賴的作業(yè)轉(zhuǎn)換為一個(gè)作業(yè)嘉裤,這樣只需寫一次HDFS郑临,且中間節(jié)點(diǎn)較少,從而大大提升作業(yè)的計(jì)算性能屑宠。
  • spark:一個(gè)通用的大數(shù)據(jù)計(jì)算框架厢洞,基于內(nèi)存計(jì)算,速度較快

優(yōu)化器

與關(guān)系型數(shù)據(jù)庫類似典奉,Hive會(huì)在真正執(zhí)行計(jì)算之前犀变,生成和優(yōu)化邏輯執(zhí)行計(jì)劃與物理執(zhí)行計(jì)劃。Hive有兩種優(yōu)化器:Vectorize(向量化優(yōu)化器)Cost-Based Optimization (CBO,成本優(yōu)化器)秋柄。

向量化優(yōu)化器

向量化優(yōu)化器會(huì)同時(shí)處理大批量的數(shù)據(jù)获枝,而不是一行一行地處理。要使用這種向量化的操作骇笔,要求表的文件格式為ORC省店,配置如下:

SET hive.vectorized.execution.enabled=true; -- 默認(rèn) false

成本優(yōu)化器

Hive的CBO是基于apache Calcite的,Hive的CBO通過查詢成本(有analyze收集的統(tǒng)計(jì)信息)會(huì)生成有效率的執(zhí)行計(jì)劃笨触,最終會(huì)減少執(zhí)行的時(shí)間和資源的利用懦傍,使用CBO的配置如下:

SET hive.cbo.enable=true; --從 v0.14.0默認(rèn)true
SET hive.compute.query.using.stats=true; -- 默認(rèn)false
SET hive.stats.fetch.column.stats=true; -- 默認(rèn)false
SET hive.stats.fetch.partition.stats=true; -- 默認(rèn)true

總結(jié)

本文主要介紹了Hive調(diào)優(yōu)的基本思路÷樱總共分為四部分粗俱,首先介紹了調(diào)優(yōu)的基本工具使用(explain、analyze);接著從表設(shè)計(jì)層面介紹了一些優(yōu)化策略(分區(qū)虚吟、分桶寸认、索引);然后介紹了數(shù)據(jù)存儲(chǔ)方面的優(yōu)化(文件格式串慰、壓縮偏塞、存儲(chǔ)優(yōu)化);最后從作業(yè)層面介紹了優(yōu)化的技巧(開啟本地模式邦鲫、JVM重用灸叼、并行執(zhí)行、fetch模式、Join優(yōu)化古今、執(zhí)行引擎與優(yōu)化器)邻耕。本文主要為Hive性能調(diào)優(yōu)提供一些思路盒发,在實(shí)際的操作過程中需要具體問題具體分析贫橙∏砬唬總之一句話富弦,重劍無鋒峻黍,為作業(yè)分配合理的資源基本上可以滿足大部分的情況旬渠,適合的就是最好的甲献,沒有必要追求狂拽酷炫的技巧撬即,應(yīng)該把更多的精力放在業(yè)務(wù)問題上立磁,因?yàn)楣ぞ叩拇嬖诘膬r(jià)值是為了解決業(yè)務(wù)問題的,切不可本末倒置剥槐。

公眾號『大數(shù)據(jù)技術(shù)與數(shù)倉』唱歧,回復(fù)『資料』領(lǐng)取大數(shù)據(jù)資料包

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市粒竖,隨后出現(xiàn)的幾起案子颅崩,更是在濱河造成了極大的恐慌,老刑警劉巖蕊苗,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沿后,死亡現(xiàn)場離奇詭異,居然都是意外死亡朽砰,警方通過查閱死者的電腦和手機(jī)尖滚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瞧柔,“玉大人漆弄,你說我怎么就攤上這事≡旃” “怎么了撼唾?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哥蔚。 經(jīng)常有香客問我倒谷,道長,這世上最難降的妖魔是什么糙箍? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任恨锚,我火速辦了婚禮,結(jié)果婚禮上倍靡,老公的妹妹穿的比我還像新娘猴伶。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布他挎。 她就那樣靜靜地躺著筝尾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪办桨。 梳的紋絲不亂的頭發(fā)上筹淫,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天,我揣著相機(jī)與錄音呢撞,去河邊找鬼损姜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛殊霞,可吹牛的內(nèi)容都是我干的摧阅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼绷蹲,長吁一口氣:“原來是場噩夢啊……” “哼棒卷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起祝钢,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤比规,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拦英,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜒什,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年疤估,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吃谣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,438評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡做裙,死狀恐怖岗憋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锚贱,我是刑警寧澤仔戈,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站拧廊,受9級特大地震影響监徘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吧碾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一凰盔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧倦春,春花似錦户敬、人聲如沸落剪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忠怖。三九已至,卻和暖如春抄瑟,著一層夾襖步出監(jiān)牢的瞬間凡泣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工皮假, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鞋拟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓惹资,卻偏偏與公主長得像贺纲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子布轿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評論 2 359