<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 17018字,需瀏覽 35分鐘

           ·

          2020-08-29 12:30






          點(diǎn)擊上方數(shù)據(jù)管道”,選擇“置頂星標(biāo)”公眾號(hào)

          干貨福利,第一時(shí)間送達(dá)


          企業(yè)中使用Hive構(gòu)建離線數(shù)倉是一種十分普遍的方案。盡管Hive的使用場(chǎng)景是通過批處理的方式處理大數(shù)據(jù),通常對(duì)處理時(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:對(duì)執(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?STRUCTstring,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)
          ??????????????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ū)和列級(jí)別的統(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ì)信息,對(duì)于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?##?日志級(jí)別
          hive.log.dir=/tmp/${user.name}?##?日志路徑
          hive.log.file=hive.log?##?日志名稱

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

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

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

          分區(qū)表

          對(duì)于一張比較大的表,將其設(shè)計(jì)成分區(qū)表可以提升查詢的性能,對(duì)于一個(gè)特定分區(qū)的查詢,只會(huì)加載對(duì)應(yīng)分區(qū)路徑的文件數(shù)據(jù),所以執(zhí)行速度會(huì)比較快。值得注意的是,分區(qū)字段的選擇是影響查詢性能的重要因素,盡量避免層級(jí)較深的分區(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對(duì)應(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ǔ)的是索引列與其對(duì)應(yīng)的block id的pair對(duì)。除了此種索引外,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???????????????????????????????
          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 :即在建表時(shí)指定文件格式,默認(rèn)是TEXTFILE
          • ALTER TABLE ... [PARTITION partition_spec] SET FILEFORMAT :修改具體表的文件格式

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

          尖叫提示

          如果要改變創(chuàng)建表的默認(rèn)文件格式,可以使用hive.default.fileformat=進(jìn)行配置,改配置可以針對(duì)所有表。同時(shí)也可以使用hive.default.fileformat.managed = 進(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對(duì)的二進(jìn)制存儲(chǔ)格式,sequence文件的優(yōu)勢(shì)是比文本格式更好壓縮,sequence文件可以被壓縮成塊級(jí)別的記錄,塊級(jí)別的壓縮是一個(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è)行組,對(duì)每個(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ù),可以針對(duì)熱數(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)對(duì)小文件的解決方案:

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

          對(duì)于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í)間還要長(zhǎng),從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)行幾秒鐘的輕量級(jí)作業(yè)時(shí),JVM啟動(dòng)進(jìn)程所耗費(fèi)的時(shí)間會(huì)比作業(yè)執(zhí)行的時(shí)間還要長(zhǎng)。Hadoop可以重用JVM,通過共享JVM以串行而非并行的方式運(yùn)行map或者reduce。JVM的重用適用于同一個(gè)作業(yè)的map和reduce,對(duì)于不同作業(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中對(duì)某些情況的查詢可以不必使用MapReduce計(jì)算??梢院?jiǎn)單地讀取表對(duì)應(yīng)的存儲(chǔ)目錄下的文件,然后輸出查詢結(jié)果到控制臺(tái)。在開啟fetch模式之后,在全局查找、字段查找、limit查找等都啟動(dòng)mapreduce,通過下面方式進(jìn)行配置:

          hive.fetch.task.conversion=more

          JOIN優(yōu)化

          普通join

          普通join又稱之為reduce端join,是一種最基本的join,并且耗時(shí)較長(zhǎng)。對(duì)于大表join小表,需要將大表放在右側(cè),即小表join大表。新版的hive已經(jīng)對(duì)小表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表對(duì)應(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指定),另外,對(duì)于大表的分桶數(shù)量必須是小表分桶數(shù)量的倍數(shù)。

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

          Sort merge bucket (SMB) join

          SMBjoin應(yīng)用與分桶表,如果兩張參與join的表是排序的,并且分桶字段相同,這樣可以使用sort-merge join,其優(yōu)勢(shì)在于不用把小表完全加載至內(nèi)存中,會(huì)讀取兩張分桶表對(duì)應(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對(duì)應(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。對(duì)于執(zhí)行引擎的選擇,會(huì)影響整體的查詢性能。使用的配置如下:

          SET?hive.execution.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ù)問題的,切不可本末倒置。

          瀏覽 42
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久精品国产亚洲AV苍井空 | 欧美色图888 | 神马影院午夜福利视频 | 蜜桃av免费 | 久久青青草大香蕉手机视频在线 |