HiveSQL最適化のアイデア

Hiveの最適化は、主に構成の最適化、SQLステートメントの最適化、タスクの最適化、およびその他のソリューションに分けられます。その中で、開発プロセスに関係する主要な部分はSQLの最適化かもしれません。

最適化の中心的なアイデアは次のとおりです:

  • データ量を減らす(例:パーティショニング、列プルーニング)

  • データの偏りを回避する(パラメーターの追加、キーの解読など)

  • 全表スキャンを避けます(たとえば、add pluspartitionなど)

  • ジョブの数を減らします(たとえば、同じ条件の結合が1つのタスクとしてまとめられます)

HQLステートメントの最適化

1.パーティションプルーニングと列プルーニングを使用します

パーティションプルーニングでは、外部アソシエーションが使用されている場合、セカンダリテーブルのフィルター条件がWhereの後に書き込まれると、テーブル全体が最初にアソシエートされ、次にフィルター処理されます。

select a.*  
from a  
left join b on  a.uid = b.uid  
where a.ds='2020-08-10'  
and b.ds='2020-08-10'

上記のSQLは主に2つの間違いを犯しました

  1. セカンダリテーブル(上記のbテーブル)のwhere条件は、結合後に書き込まれます。これにより、テーブル全体が最初にフィルターパーティションに関連付けられます。

注:テーブルのwhere条件も結合後に書き込まれますが、テーブルは述部をプッシュダウンします。つまり、最初にwhere条件を実行してから結合を実行しますが、bテーブルは述語!

  1. onの条件はnull値をフィルタリングしません.2つのデータテーブルにnull値が多数ある場合、データは歪められます。

正しいスペル

select a.*  
from a  
left join b on (d.uid is not null and a.uid = b.uid and b.ds='2020-08-10') 
where a.ds='2020-08-10'

null値も必要な場合は、条件に応じて変換するか、別途取り出す必要があります

select a.*  
from a  
left join b on (a.uid is not null and a.uid = b.uid and b.ds='2020-08-10')  
where a.ds='2020-08-10'  
union all  
select a.* from a where a.uid is null 

また:

select a.*  
from a  
left join b on   
case when a.uid is null then concat("test",RAND()) else a.uid end = b.uid and b.ds='2020-08-10'  
where a.ds='2020-08-10'

または(サブクエリ):

select a.*  
from a  
left join   
(select uid from where ds = '2020-08-10' and uid is not null) b on a.uid = b.uid 
where a.uid is not null  
and a.ds='2020-08-10'

2.COUNTDISTINCTを使用しないようにしてください

COUNT DISTINCT操作はReduceタスクによって完了する必要があるため、このReduceが処理する必要のあるデータの量が多すぎて、ジョブ全体を完了することが困難になります。通常、COUNTDISTINCTはGROUPBYに置き換えられてからCOUNT、もう1つのジョブが使用されますが、完了するために使用されますが、大量のデータの場合、これは間違いなく価値があります。

select count(distinct uid)  
from test  
where ds='2020-08-10' and uid is not null  

次のように変換されます。

select count(a.uid)  
from   
(select uid 
 from test 
 where uid is not null and ds = '2020-08-10' 
 group by uid
) a

3.として使用

結合によって生成されるシャッフルに加えて、Hiveクエリの効率を低下させるもう1つの要因は、サブクエリです。SQLステートメントのサブクエリを最小限に抑えます。そのままで、ステートメントで使用されるサブクエリを事前に抽出して(一時テーブルと同様)、クエリ全体のすべてのモジュールがクエリ結果を呼び出すことができるようにします。asを使用すると、Hiveが異なる部分で同じサブクエリを繰り返し計算するのを防ぐことができます。

select a.*  
from  a  
left join b on  a.uid = b.uid  
where a.ds='2020-08-10'  
and b.ds='2020-08-10'  

次のように変換できます。

with test1 as 
(
select uid  
from b  
where ds = '2020-08-10' and uid is not null  
)  
select a.*  
from a  
left join test1 on a.uid = test1.uid  
where a.ds='2020-08-10' and a.uid is not null

4.サイズテーブルの結合

結合操作を使用してクエリを作成する場合の経験則があります。エントリの少ないテーブル/サブクエリは、結合演算子の左側に配置する必要がありますその理由は、結合操作の削減フェーズでは、結合演算子の左側にあるテーブルの内容がメモリにロードされ、左側にエントリが少ないテーブルを配置すると、 OOMエラー。ただし、新しいバージョンのハイブでは、スモールテーブルJOINラージテーブルとラージテーブルJOINスモールテーブルが最適化されています。左右の小さなテーブルに明らかな違いはありません。ただし、結合の過程で、小さなテーブルを前面に配置することで、データ量を適切に削減し、効率を向上させることができます。

5.データスキュー

データスキューの原理は既知です。つまり、1つまたは複数のキーがデータ全体の90%を占めるため、このキーと同じキーの処理によってタスク全体の効率が低下します。メモリ損失オーバーフローを引き起こすために一緒に集約される可能性があります。

データスキューは、シャッフル中にのみ発生します。シャッフル操作をトリガーする可能性のある一般的に使用される演算子は次のとおりです。distinct、groupByKey、reduceByKey、aggregateByKey、join、cogroup、repartitionなど。データスキューが発生する場合は、コードでこれらの演算子のいずれかを使用していることが原因である可能性があります。

ハイブのデータスキューの一般的な処理スキーム

パラメータ調整による一般的な方法:

set hive.map.aggr=true;  
set hive.groupby.skewindata = ture;

オプションがtrueに設定されている場合、生成されたクエリプランには2つのMapReduceタスクがあります。

最初のMapReduceでは、マップの出力結果セットがレデューサー間でランダムに分散され、各レデューサーが部分的な集計操作を実行して結果を出力します。

この処理の結果、負荷分散の目的を達成するために、同じGroupByKeyが異なるレデューサーに分散される可能性があります。

次に、2番目のMapReduceタスクが前処理されたデータ結果に従ってReduce by Group By Keyに配布され(このプロセスにより、同じGroup By Keyが同じReduceに配布されることが保証されます)、最後に最終的な集計操作が完了します。

しかし、このソリューションは私たちにとってブラックボックスであり、制御することはできません。

一般的な解決策は、対応するキー値を分割することです。

例えば:

select a.*  
from a  
left join b on  a.uid = b.uid  
where a.ds='2020-08-10'  
and b.ds='2020-08-10'  

キーの90%がヌルの場合、データの偏りは必然的に発生します。

select a.uid  
from test1 as a  
join(  
   select case when uid is null then cast(rand(1000000) as int)  
   else uid  
   from test2 where ds='2020-08-10') b   
on a.uid = b.uid  
where a.ds='2020-08-10'  

もちろん、これは理論的な解決策にすぎません。

通常の解決策はnullでフィルタリングすることですが、これは日常の状況では特別なキーではありません。

したがって、日常のニーズの場合にこの種のデータの偏りに対処する方法は次のとおりです。

  1. キーのセットが取得されるサンプルサンプリング。

  2. 特定のルールに従って、セット内のキーに乱数を追加します。

  3. 結合が実行されると、データの偏りは分割されるため回避されます。

  4. 処理結果では、以前に追加された乱数が元のデータに分割されます。

もちろん、これらの最適化はすべてSQL自体に対して最適化されており、一部はパラメーター設定によって調整されますが、ここでは詳しく説明しません。

しかし、最適化の中心的な考え方は同じです:

  1. データ量を減らす

  2. データの偏りを避ける

  3. ジョブの数を減らす

  4. 仮想コアポイント:ビジネスロジックに従って全体的なビジネス実装を最適化します。

  5. 仮想ソリューション:prestoやimpalaなどの特別なクエリエンジンを使用し、Sparkコンピューティングエンジンを使用してMR/TEZを置き換えます

この記事は公式アカウント[ビッグデータを学ぶための5分]で公開され、キーワード[攻略][インタビュー][履歴書]が公式アカウントで送信され、対応する超強力なデータ収集を取得します

おすすめ

転載: blog.csdn.net/helloHbulie/article/details/122184921