ハイブチューニング
序文
ハイブのチューニングをマスターしたかどうかは、データエンジニアが資格を持っているかどうかの重要な指標であると言っても過言ではありません。ハイブの調整には、圧縮とストレージの調整、パラメーターの調整、sqlの調整、データの傾きの調整、および小さなファイルの問題が含まれます。
1.データの圧縮と保存の形式
- マップステージはデータ圧縮を出力します。このステージでは、CPUオーバーヘッドの低いアルゴリズムが推奨されます。
set hive.exec.compress.intermediate=true
set mapred.map.output.compression.codec= org.apache.hadoop.io.compress.SnappyCodec
set mapred.map.output.compression.codec=com.hadoop.compression.lzo.LzoCodec;
- 最終出力結果を圧縮します
set hive.exec.compress.output=true
set mapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec
## 当然,也可以在hive建表时指定表的文件格式和压缩编码
結論として、一般的にorcfile / parquet + snappyを選択します
2.パーティションとバケットの合理的な使用
パーティショニングとは、テーブルのデータを物理的に異なるフォルダに分割することです。これにより、クエリ時に読み取るパーティションディレクトリを正確に指定でき、読み取られるデータの量が減ることはありません。
バケット化とは、指定した列のハッシュをハッシュした後、テーブルデータを異なるファイルに分割することです。将来クエリを実行するときに、ハイブはバケット化構造に従ってデータの行が配置されているバケット化ファイルをすばやく見つけることができるため、読み取り効率が向上します。
3.ハイブパラメータの最適化
// 让可以不走mapreduce任务的,就不走mapreduce任务
hive> set hive.fetch.task.conversion=more;
// 开启任务并行执行
set hive.exec.parallel=true;
// 解释:当一个sql中有多个job时候,且这多个job之间没有依赖,则可以让顺序执行变为并行执行(一般为用到union all的时候)
// 同一个sql允许并行任务的最大线程数
set hive.exec.parallel.thread.number=8;
// 设置jvm重用
// JVM重用对hive的性能具有非常大的 影响,特别是对于很难避免小文件的场景或者task特别多的场景,这类场景大多数执行时间都很短。jvm的启动过程可能会造成相当大的开销,尤其是执行的job包含有成千上万个task任务的情况。
set mapred.job.reuse.jvm.num.tasks=10;
// 合理设置reduce的数目
// 方法1:调整每个reduce所接受的数据量大小
set hive.exec.reducers.bytes.per.reducer=500000000; (500M)
// 方法2:直接设置reduce数量
set mapred.reduce.tasks = 20
// map端聚合,降低传给reduce的数据量
set hive.map.aggr=true
// 开启hive内置的数倾优化机制
set hive.groupby.skewindata=true
4.sqlの最適化
4.1条件の最適化
最適化前(リレーショナルデータベースは考慮せずに自動的に最適化されます)
select m.cid,u.id
from order m join customer u
on( m.cid =u.id )where m.dt='20180808';
最適化後(条件が縮小側ではなくマップ側で実行される場合)
select m.cid,u.id
from (select * from order where dt='20180818') m
join customer u
on( m.cid =u.id);
4.2ユニオンの最適化
unionを使用しないようにしてください(unionは重複レコードを削除します)が、union allを使用してから、groupbyを使用して重複を削除します
4.3カウントの明確な最適化
count(distinct cloumn)を使用せず、サブクエリを使用します
select count(1)
from (select id from tablename group by id) tmp;
4.4参加する代わりにで使用する
1つのテーブルのフィールドに基づいて別のテーブルを制約する必要がある場合は、joinの代わりにinを使用してみてください。Inはjoinよりも高速です。
select id,name from tb1 a join tb2 b on(a.id = b.id);
select id,name from tb1 where id in(select id from tb2);
4.5サブクエリの最適化
サブクエリのGROUPby、COUNT(DISTINCT)、MAX、MINを削除します。ジョブの数を減らすことができます。
4.6参加の最適化
Common / shuffle / Reduce JOIN接続はreduceフェーズで発生し、大きなテーブルを大きなテーブルに接続するのに適しています(デフォルトの方法)
マップ結合:接続はマップフェーズで発生し、小さなテーブルを大きなテーブルに接続し、
大きなテーブルをファイルから接続するのに適しています
メモリに保存されている小さなデータテーブルの読み取り(Hiveは自動的に最適化され、小さなテーブルとキャッシュを自動的に決定します)
set hive.auto.convert.join=true;
SMB結合
Sort-Merge -Bucket Joinは、バケットテーブルの概念を使用して、大きなテーブルから大きなテーブルへの接続を最適化します。カルテシアン製品の結合はバケットで発生します(2つのバケットテーブルを結合する必要があります)
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;
5.データスキュー
パフォーマンス:タスクの進行状況は99%(または100%)で長期間維持されます。タスク監視ページを確認すると、少数(1つまたは複数)の削減サブタスクのみが完了していないことがわかります。処理されるデータの量が他のreduceと大きく異なるためです。
理由:リデュースの入力データ量が他のリデュースの入力データ量よりもはるかに多い
5.1sql自体によって引き起こされる傾き
1)
groupbyのgroupbyにデータスキューがある場合、group byのディメンションを細かくすることはできますか?細かくできない場合は、元のグループキーにランダムな数値を追加し、グループ化して1回集計します。結果からランダムな数値を削除してから、グループ化して集計します。
結合時にnull結合キーが多数ある場合は、nullをランダムな値に変換して集約を回避できます。
2)カウント(個別)
状況:特殊値が多すぎる
結果:この特殊値の処理を減らすには時間がかかります。削減タスクは1つだけです。
解決策:個別にカウントする場合は、null値を個別に処理します。たとえば、null値を直接フィルタリングできます。行に
加えて、最終結果に1を加えます。グループ化する必要のある他の計算がある場合は、値が空のレコードを個別に処理してから、他の計算結果と組み合わせることができます。
3)異なるデータタイプの関連付けによって引き起こされるデータスキュー
:たとえば、userテーブルのuser_idフィールドはintであり、ログテーブルのuser_idフィールドにはstringタイプとintタイプの両方があります。user_idに従って2つのテーブルの結合操作が実行される場合。
結果:この特別な値のリデュースの処理には時間がかかります。リデュースタスクは1つだけです。
デフォルトのハッシュ操作はintタイプIDに従って割り当てられ、文字列タイプIDのすべてのレコードが
レデューサーに割り当てられます。
解決策:数値タイプを文字列タイプに変換し
ます。select *ユーザーから
左外部結合ログb
on a.usr_id = cast(b.user_id as string)
4)mapjoin
5.2ビジネスデータ自体の特性(ホットキーがあります)
結合の各入力は比較的大きく、ロングテールはホット値によって発生します。ホット値と非ホット値を別々に処理すると、データ
キー自体が不均一に分散されます。
キーにランダムな数値を追加したり、reduceタスクの数を増やしたりできます。
5.3データスキュー時にロードバランシングを有効にする
set hive.groupby.skewindata = true;
アイデア:最初にランダムに配布して処理し、次にキーグループに従って配布して処理します。
操作:オプションがtrueに設定されている場合、生成されたクエリプランには2つのMRJobがあります。
最初のMRJobでは、マップの出力結果セットがランダムにReduceに配布されます。各Reduceは、部分的な集計操作を実行して結果を出力します。処理の結果、同じGroupByキーが異なるReduceに配布される可能性があります。負荷分散の目的を達成するため。
次に、2番目のMRJobは、前処理されたデータ結果に従ってGroupBy Keyに従ってReduceに配布され(このプロセスにより、同じ元のGroupBy Keyが同じReduceに配布されることが保証されます)、最後に最終的な集計操作が完了します。
5.4ヌル値の分布を制御する
空のキーを文字列とランダム数または純粋なランダム数に変換して、空の値が原因で歪んだデータが複数のレデューサーに分割されないようにします。
注:異常値が不要な場合は、事前にwhere条件でフィルターで除外することをお勧めします。これにより、計算量を大幅に削減できます。
6.小さなファイルをマージします
小さなファイルが生成される場所は3つあります。マップ入力、マップ出力、出力の削減です。小さなファイルが多すぎると、ハイブ分析の効率にも影響します。
マップ入力の小さなファイルのマージを設定します
set mapred.max.split.size=256000000;
//一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)
set mapred.min.split.size.per.rack=100000000;
//执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
マップ出力をマージして出力を減らすための関連パラメーターを設定します。
//设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true
//设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true
//设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000
7.sqlの実行計画を表示します
sql
は、sqlの実行計画を表示し、ビジネスロジックを最適化し、ジョブデータの量を減らすことを学びます。チューニングにも非常に重要です