ハイブのチューニング方法

1 実行計画(説明)

1.1 基本的な構文

HIVE には、クエリの実行計画を表示する EXPLAIN コマンドが用意されており、この実行計画は、基礎となる原理、Hive の調整、データ スキューのトラブルシューティングを理解するのに非常に役立ちます。

使用構文は次のとおりです。

EXPLAIN [EXTENDED|CBO|AST|DEPENDENCY|AUTHORIZATION|LOCKS|VECTORIZATION|ANALYZE] query

パラメータの説明:

EXTENDED: プランに関する追加情報を出力するには、extended を追加します。これは通常、ファイル名などの物理情報です。この追加情報は私たちにとってあまり役に立ちません

CBO: Calcite オプティマイザーによって生成されたプランを出力します。CBO はハイブのバージョン 4.0.0 からサポートします

AST: 出力クエリの抽象構文ツリー。AST はハイブ 2.1.0 バージョンで削除されました。バグがあります。AST をダンプすると OOM エラーが発生する可能性があります。バージョン 4.0.0 で修正される予定です。

DEPENDENCY: EXPLAIN ステートメントで依存関係を使用すると、プランの入力に関する追加情報が生成されます。入力のさまざまなプロパティを表示します

AUTHORIZATION: クエリ (存在する場合) と承認の失敗を実行するために承認が必要なすべてのエンティティを表示します。

ロック: これは、指定されたクエリを実行するためにシステムがどのロックを取得するかを知るのに役立ちます。LOCKS はハイブ 3.2.0 からサポートされています

ベクトル化:Map と Reduce がベクトル化されない理由を示す詳細を EXPLAIN 出力に追加します。Hive 2.3.0 以降でサポートされています

分析: 計画に実際の行数の注釈を付けます。Hive 2.2.0 以降でサポートされています

1.2 実際の操作

-- 执行
explain select * from emp;
-- 得到如下结果
STAGE DEPENDENCIES:
  Stage-0 is a root stage

STAGE PLANS:
  Stage: Stage-0
    Fetch Operator
      limit: -1
      Processor Tree:
        TableScan
          alias: emp
          Statistics: Num rows: 1 Data size: 6570 Basic stats: COMPLETE Column stats: NONE
          Select Operator
            expressions: empno (type: int), ename (type: string), job (type: string), mgr (type: int), hiredate (type: string), sal (type: double), comm (type: double), deptno (type: int)
            outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, _col6, _col7
            Statistics: Num rows: 1 Data size: 6570 Basic stats: COMPLETE Column stats: NONE
            ListSink
  1. MRのExplainを実行する
STAGE DEPENDENCIES:
  Stage-1 is a root stage
  Stage-0 depends on stages: Stage-1

STAGE PLANS:
  Stage: Stage-1
    Map Reduce
      Map Operator Tree:
          TableScan
            alias: emp
            Statistics: Num rows: 1 Data size: 6570 Basic stats: COMPLETE Column stats: NONE
            Select Operator
              expressions: sal (type: double), deptno (type: int)
              outputColumnNames: sal, deptno
              Statistics: Num rows: 1 Data size: 6570 Basic stats: COMPLETE Column stats: NONE
              Group By Operator
                aggregations: sum(sal), count(sal)
                keys: deptno (type: int)
                mode: hash
                outputColumnNames: _col0, _col1, _col2
                Statistics: Num rows: 1 Data size: 6570 Basic stats: COMPLETE Column stats: NONE
                Reduce Output Operator
                  key expressions: _col0 (type: int)
                  sort order: +
                  Map-reduce partition columns: _col0 (type: int)
                  Statistics: Num rows: 1 Data size: 6570 Basic stats: COMPLETE Column stats: NONE
                  value expressions: _col1 (type: double), _col2 (type: bigint)
      Execution mode: vectorized
      Reduce Operator Tree:
        Group By Operator
          aggregations: sum(VALUE._col0), count(VALUE._col1)
          keys: KEY._col0 (type: int)
          mode: mergepartial
          outputColumnNames: _col0, _col1, _col2
          Statistics: Num rows: 1 Data size: 6570 Basic stats: COMPLETE Column stats: NONE
          Select Operator
            expressions: _col0 (type: int), (_col1 / _col2) (type: double)
            outputColumnNames: _col0, _col1
            Statistics: Num rows: 1 Data size: 6570 Basic stats: COMPLETE Column stats: NONE
            File Output Operator
              compressed: false
              Statistics: Num rows: 1 Data size: 6570 Basic stats: COMPLETE Column stats: NONE
              table:
                  input format: org.apache.hadoop.mapred.SequenceFileInputFormat
                  output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
                  serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe

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

2 フェッチキャプチャ

フェッチ キャプチャとは、特定の状況において Hive のクエリで MapReduce 計算を使用する必要がないことを意味します。例: SELECT * FROMemployees; この場合、Hive は単純に従業員に対応するストレージ ディレクトリ内のファイルを読み取り、クエリ結果をコンソールに出力します。
hive-default.xml.template ファイルでは、hive.fetch.task.conversion のデフォルトは more であり、古いバージョンの hive のデフォルトは minimum です。この属性が more に変更されると、mapreduce はグローバル検索に使用されなくなります。検索、および検索を制限します。

<property>
    <name>hive.fetch.task.conversion</name>
    <value>more</value>
    <description>
      Expects one of [none, minimal, more].
      Some select queries can be converted to single FETCH task minimizing latency.
      Currently the query should be single sourced not having any subquery and should not have any aggregations or distincts (which incurs RS), lateral views and joins.
      0. none : disable hive.fetch.task.conversion
      1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
      2. more  : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
    </description>
</property>

3 ローカルモード

ほとんどの Hadoop ジョブでは、大規模なデータ セットを処理するために Hadoop が提供する完全なスケーラビリティが必要です。ただし、Hive への入力データの量が非常に少ない場合があります。この場合、クエリによってトリガーされる実行時間は、実際のジョブの実行時間よりも大幅に長くなる可能性があります。これらのほとんどの場合、Hive はローカル モードの単一マシン上ですべてのタスクを処理できます。データセットが小さい場合、実行時間を大幅に短縮できます。

ユーザーは、hive.exec.mode.local.auto の値を true に設定することで、必要に応じて Hive がこの最適化を自動的に開始できるようにすることができます。

set hive.exec.mode.local.auto=true;  --开启本地mr
--设置local mr的最大输入数据量,当输入数据量小于这个值时采用local  mr的方式,默认为134217728,即128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
-- 设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,默认为4
set hive.exec.mode.local.auto.input.files.max=10;

4 テーブルの最適化

4.1 小さいテーブルと大きいテーブルの結合(MapJoin)

キーが比較的分散しており、データ量が少ないテーブルを結合の左側に配置すると、メモリ オーバーフロー エラーの可能性を効果的に低減できます。さらに、マップ結合を使用して小さなディメンション テーブル (レコード数が 1000 未満) を作成できます。高度なメモリ。結合はマップ側で行われます。

実際のテストでは、新しいバージョンのハイブが、小さなテーブルの JOIN 大きなテーブルと大きなテーブルの JOIN 小さなテーブルを最適化していることがわかりました。小さな時計は左右で明らかな違いはありません。

-- 测试大表JOIN小表和小表JOIN大表的效率
-- 开启MapJoin参数设置
	-- 设置自动选择Mapjoin,默认为true
	set hive.auto.convert.join = true;
	-- 大表小表的阈值设置(默认25M以下认为是小表)
	set hive.mapjoin.smalltable.filesize = 25000000;

MapJoin の動作メカニズム

4.2 大きなテーブルの結合 大きなテーブル

4.2.1 空の KEY フィルタリング

結合タイムアウトの原因は、一部のキーが多すぎるデータに対応し、同じキーに対応するデータが同じリデューサーに送信されるため、メモリが不足することが原因である場合があります。この時点で、これらの異常なキーを注意深く分析する必要があり、多くの場合、これらのキーに対応するデータは異常なデータであるため、SQL ステートメントでフィルタリングする必要があります。たとえば、キーに対応するフィールドが空の場合、操作は次のようになります。

  1. 履歴サーバーの構成
<!--配置mapred-site.xml-->
<property>
<name>mapreduce.jobhistory.address</name>
<value>hadoop102:10020</value>
</property>
<property>
    <name>mapreduce.jobhistory.webapp.address</name>
    <value>hadoop102:19888</value>
</property>
-- 启动历史服务器
sbin/mr-jobhistory-daemon.sh start historyserver

ジョブ履歴を表示http://hadoop102:19888/jobhistory

  1. 元のデータ テーブル、空の ID テーブル、マージされたデータ テーブルを作成する
-- 创建空id表
create table nullidtable(
    id bigint, 
    t bigint, 
    uid string, 
    keyword string, 
    url_rank int, 
    click_num int, 
    click_url string
) 
row format delimited fields terminated by '\t';
  1. 元のデータと空のIDデータをそれぞれ対応するテーブルにロードします
hive (default)> load data local inpath '/opt/module/hive/datas/nullid' into table nullidtable;
  1. テストは空の ID をフィルターしません
hive (default)> insert overwrite table jointable select n.* from nullidtable n
left join bigtable o on n.id = o.id;
  1. テストフィルターの空のID
hive (default)> insert overwrite table jointable select n.* from (select * from nullidtable where id is not null ) n  left join bigtable o on n.id = o.id;

4.2.2 空キー変換

特定のキーが空であるにもかかわらず、それに対応するデータが多数存在する場合がありますが、該当するデータは異常なデータではないため、結合結果に含める必要があります。このとき、空のキー フィールドにランダムな値を割り当てることができます。表 a では、データをランダムにし、さまざまなリデューサーに均等に分散します。

Null 値がランダムに分散されていない場合、次の操作が実行されます。

  1. 設定 5 数字を減らす
set mapreduce.job.reduces = 5;
  1. 2 つのテーブルを結合する
insert overwrite table jointable
select n.* from nullidtable n left join bigtable b on n.id = b.id;

データ スキューがあり、一部の Reducer のリソース消費量が他の Reducer よりもはるかに大きいことがわかります。

空の null 値をランダムに配布する場合、次の操作が実行されます。

  1. 設定 5 数字を減らす
set mapreduce.job.reduces = 5;
  1. 2 つのテーブルを結合する
insert overwrite table jointable
select n.* from nullidtable n full join bigtable o on 
nvl(n.id,rand()) = o.id;

4.2.3 SMB(ソート・マージ・バケット結合)

(1) 2 番目の大きなテーブルを作成する

create table bigtable2(
    id bigint,
    t bigint,
    uid string,
    keyword string,
    url_rank int,
    click_num int,
    click_url string)
row format delimited fields terminated by '\t';
load data local inpath '/opt/module/data/bigtable' into table bigtable2;

大きなテーブルの直接結合をテストする

insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable s
join bigtable2 b
on b.id = s.id;

(2) バケット テーブル 1 を作成します。バケットの数は、使用可能な CPU コアの数を超えてはいけません。

create table bigtable_buck1(
    id bigint,
    t bigint,
    uid string,
    keyword string,
    url_rank int,
    click_num int,
    click_url string)
clustered by(id) 
sorted by(id)
into 6 buckets
row format delimited fields terminated by '\t';

insert into bigtable_buck1 select * from bigtable; 

(3) サブ通信テーブル 2 を作成します。バケットの数は、使用可能な CPU コアの数を超えないようにしてください。

create table bigtable_buck2(
    id bigint,
    t bigint,
    uid string,
    keyword string,
    url_rank int,
    click_num int,
    click_url string)
clustered by(id)
sorted by(id) 
into 6 buckets
row format delimited fields terminated by '\t';

insert into bigtable_buck2 select * from bigtable; 

(4) パラメータの設定

set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;

(5) テスト

insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable_buck1 s
join bigtable_buck2 b
on b.id = s.id;

4.3 グループ化

デフォルトではマップ段階で同じキーデータがreduceに分散されるため、キーデータが大きすぎるとデータスキューが発生します。

すべての集約操作をreduce側で完了する必要はなく、多くの集約操作は最初にmap側で部分的に集約し、最後にreduce側で最終結果を取得できます。

  1. マップ側の集計パラメータ設定を有効にする
-- 是否在Map端进行聚合,默认为True
set hive.map.aggr = true
-- 在Map端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000
-- 有数据倾斜的时候进行负载均衡(默认是false)
set hive.groupby.skewindata = true

このオプションを true に設定すると、生成されたクエリ プランには 2 つの MR ジョブが含まれます。最初の MRJob では、Map の出力結果がランダムに Reduce に分散され、各 Reduce が部分的な集計操作を実行して結果を出力します。この処理の結果、同じ Group By Key が異なる Reduce に分散される可能性があります。負荷分散の目的を達成するために、2 番目の MRJob は、Group By Key に従って前処理されたデータ結果を Reduce に分散し (このプロセスにより、同じ GroupBy キーが同じ Reduce に分散されることが保証されます)、最後に、最後の集計操作。

4.4 カウント (個別) 重複排除統計

データ量が少ないときは問題ありませんが、データ量が多いときは、COUNT DISTINCT操作をReduceタスクで完了させる必要があるため、このReduceで処理するデータ量が多くなりすぎてしまい、通常、COUNT DISTINCT は GROUP BY に置き換えてから COUNT を使用しますが、group by によって生じるデータの偏りに注意する必要があります。

実用的

-- 创建一张大表
hive (default)> create table bigtable(id bigint, time bigint, uid string, keyword
string, url_rank int, click_num int, click_url string) row format delimited
fields terminated by '\t';
-- 加载数据
hive (default)> load data local inpath '/opt/module/datas/bigtable' into table bigtable;
-- 设置5个reduce个数
set mapreduce.job.reduces = 5;
-- 执行去重id查询
hive (default)> select count(distinct id) from bigtable;
Stage-Stage-1: Map: 1  Reduce: 1   Cumulative CPU: 7.12 sec   HDFS Read: 120741990 HDFS Write: 7 SUCCESS
Total MapReduce CPU Time Spent: 7 seconds 120 msec
OK
c0
100001
Time taken: 23.607 seconds, Fetched: 1 row(s)
-- 采用GROUP by去重id
hive (default)> select count(id) from (select id from bigtable group by id) a;
Stage-Stage-1: Map: 1  Reduce: 5   Cumulative CPU: 17.53 sec   HDFS Read: 120752703 HDFS Write: 580 SUCCESS
Stage-Stage-2: Map: 1  Reduce: 1   Cumulative CPU: 4.29 sec2   HDFS Read: 9409 HDFS Write: 7 SUCCESS
Total MapReduce CPU Time Spent: 21 seconds 820 msec
OK
_c0
100001
Time taken: 50.795 seconds, Fetched: 1 row(s)

完了するまでにもう 1 つのジョブが必要になりますが、大量のデータの場合は、それだけの価値があります。

4.5 デカルト積

デカルト積を避けるようにしてください。結合するときは、on 条件を追加しないでください。または、on 条件が無効です。Hive は、デカルト積を完成させるために 1 つのリデューサーのみを使用できます。

4.6 行と列のフィルタリング

列の処理: SELECT では必要な列のみを取得し、パーティションがある場合は可能な限りパーティション フィルターを使用し、SELECT * の使用を減らします。

行処理: パーティション プルーニングで、外部関連付けを使用する場合、サブ テーブルのフィルター条件が Where の後に記述されている場合、テーブル全体が最初に関連付けられてからフィルター処理されます。次に例を示します。

事例の実践:

-- 测试先关联两张表,再用where条件过滤
hive (default)> select o.id from bigtable b
join bigtable  o.id = b.id
where o.id <= 10;
Time taken: 34.406 seconds, Fetched: 100 row(s)
-- 通过子查询后,再关联表
hive (default)> select b.id from bigtable b
join (select id from bigtable where id <= 10 ) o on b.id = o.id;
Time taken: 30.058 seconds, Fetched: 100 row(s)

4.7 MapとReduceの数を適切に設定する

1) 通常、ジョブは入力ディレクトリを通じて 1 つ以上のマップ タスクを生成します。
主な決定要因は、入力ファイルの総数、入力ファイルのサイズ、およびクラスターによって設定されたファイル ブロック サイズです。

2) マップは多いほうが良いですか?
答えは否定的です。タスクに多数の小さなファイル (128m のブロック サイズよりもはるかに小さい) が含まれる場合、それぞれの小さなファイルはブロックとして扱われ、マップ タスクで完了します。マップ タスクの起動および初期化時間は、ロジックよりもはるかに長くなります。処理時間が長くなると、多くのリソースが無駄になります。また、同時に実行できるマップの数には制限があります。

3) 各マップが 128 メートル近くのファイル ブロックを処理することが保証されているので、座ってリラックスできますか?
答えは必ずしもそうではありません。たとえば、127m のファイルがある場合、通常はマップを使用してそれを完成させますが、このファイルには 1 つまたは 2 つの小さなフィールドしかありませんが、数千万のレコードがあり、マップ処理のロジックがより複雑になると、マップタスクを使用する必要があり、これも時間がかかります。

上記の問題 2 と 3 については、マップの数を減らすか、マップの数を増やすかの 2 つの方法で解決する必要があります。

4.7.1 複雑なファイルのマップの数を増やす

入力ファイルが大きく、タスク ロジックが複雑で、マップの実行が非常に遅い場合は、マップの数を増やして各マップで処理されるデータ量を減らし、それによってタスクの実行効率を向上させることを検討できます。

マップを増やす方法は次のとおりです。 computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M という式に従って、maxSize の最大値を調整します。マップの数を増やすには、maxSize の最大値を blocksize より小さくします。

事例の実践:

-- 执行查询
hive (default)> select count(*) from emp;
Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1
-- 设置最大切片值为100个字节
hive (default)> set mapreduce.input.fileinputformat.split.maxsize=100;
hive (default)> select count(*) from emp;
Hadoop job information for Stage-1: number of mappers: 6; number of reducers: 1

4.7.2 小さなファイルを結合する

1) マップの数を減らすために、マップの実行前に小さいファイルをマージします。 CombineHiveInputFormat には、小さいファイル (システムのデフォルト形式) をマージする機能があります。HiveInputFormat には小さなファイルをマージする機能はありません。

set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

2) Map-Reduce タスクの最後に小さなファイルをマージするための設定:

-- 在map-only任务结束时合并小文件,默认true
SET hive.merge.mapfiles = true;
-- 在map-reduce任务结束时合并小文件,默认false
SET hive.merge.mapredfiles = true;
-- 合并文件的大小,默认256M
SET hive.merge.size.per.task = 268435456;
-- 当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge
SET hive.merge.smallfiles.avgsize = 16777216;

4.7.3 Reduce の数を合理的に設定する

1) リデュース方法1の回数を調整する

-- 每个Reduce处理的数据量默认是256MB
hive.exec.reducers.bytes.per.reducer=256000000
-- 每个任务最大的reduce数,默认为1009
hive.exec.reducers.max=1009
-- 计算reducer数的公式
N=min(参数2,总输入数据量/参数1)

2) リデュース方法2の回数を調整する

-- 在hadoop的mapred-default.xml文件中修改
-- 设置每个job的Reduce个数
set mapreduce.job.reduces = 15;

3) リデュース数は多ければ多いほど良いわけではありません

  1. 過剰な起動と初期化の削減も時間とリソースを消費します。
  2. また、reduce の数だけ出力ファイルが存在することになりますが、小さいファイルが多数生成された場合、その小さいファイルを次のタスクの入力として使用すると、小さいファイルが多すぎるという問題も発生します。

Reduce の数を設定するときは、大量のデータを処理するために適切な Reduce の数を使用する、1 つの Reduce タスクで処理されるデータの量を適切にする、という 2 つの原則も考慮する必要があります。

4.8 並列実行

ive はクエリを 1 つ以上のステージに変換します。このようなステージには、MapReduce ステージ、サンプリング ステージ、マージ ステージ、リミット ステージなどがあります。または、Hive の実行中に必要となる可能性のあるその他のステージ。デフォルトでは、Hive は一度に 1 つのステージのみを実行します。ただし、特定のジョブには多くのステージが含まれている場合があり、これらのステージは完全に相互依存していない場合があります。つまり、一部のステージは並行して実行できるため、ジョブ全体の実行時間が短縮される可能性があります。ただし、より多くのステージを並行して実行できる場合、ジョブはより速く完了する可能性があります。

パラメータ hive.exec.Parallel を true に設定すると、同時実行を有効にすることができます。ただし、共有クラスターでは、ジョブ内の並列ステージが増えるとクラスターの使用率が増加することに注意してください。

set hive.exec.parallel=true;              -- 打开任务并行执行
set hive.exec.parallel.thread.number=16;  -- 同一个sql允许最大并行度,默认为8。

もちろん、システム リソースが比較的空いている場合には利点がありますが、そうでない場合、リソースがないと並列処理は開始されません。

4.9 ストリクトモード

Hive は以下を設定することで、一部の危険な操作を防ぐことができます。

  1. パーティションテーブルはパーティションフィルタリングを使用しません

    hive.strict.checks.no.partition.filter が true に設定されている場合、パーティション テーブルの場合、where ステートメントに範囲を制限するパーティション フィールド フィルター条件が含まれていない限り、実行は許可されません。つまり、ユーザーはすべてのパーティションをスキャンすることはできません。この制限の理由は、通常、パーティション化されたテーブルには非常に大きなデータ セットがあり、データが急速に増大するためです。パーティション制約のないクエリは、テーブルを処理するために許容できないほど大量のリソースを消費する可能性があります。

  2. 制限なしで注文フィルターを使用する

hive.strict.checks.orderby.no.limit が true に設定されている場合、order by ステートメントを使用するクエリには、limit ステートメントを使用する必要があります。order by は並べ替え処理を実行するためにすべての結果データを同じ Reducer に分散して処理するため、ユーザーがこの LIMIT ステートメントを増やすことを強制すると、Reducer が長時間実行されなくなる可能性があります。

  1. デカルト積

hive.strict.checks.cartesian.product が true に設定されている場合、デカルト積クエリは制限されます。リレーショナル データベースに精通しているユーザーは、JOIN クエリを実行するときに ON ステートメントの代わりに where ステートメントを使用して、リレーショナル データベースの実行オプティマイザーが WHERE ステートメントを ON ステートメントに効率的に変換できるようにすることを期待するかもしれません。残念ながら、Hive はこの最適化を実行しないため、テーブルが十分に大きい場合、このクエリは制御不能になる可能性があります。

おすすめ

転載: blog.csdn.net/meng_xin_true/article/details/126060696