Hiveのクエリを何倍も速くする４つの方法

# はじめに

HiveはHDFS上のデータをSQLで操作できるHadoopのエコシステムです。Facebook社により開発され、現在はApacheのトッププロジェクトの一つです。

Hiveがリリースされてから7年ほど時間が経ちました。  その間に他のビッグデータ用のSQLエンジンがいくつか登場しました。  これらのSQLエンジンの多くは、Hiveが苦手としていた低レイテンシなクエリの実行に応えることにフォーカスしています。

従来HiveのバックエンドはMapReduceで動いており、クエリを実行すると完了するまで数分から数十分、数時間の時間がかかりました。そのためアナリストの解析用途で利用するのは難しく、主にデイリーやアワリーの集計などのバッチ処理として利用されてきました。

しかしながら、現在もHiveの開発・改善は非常に活発に行われています。特にここ１〜２年の間にHortonworks社を中心としたStingerというHiveを高速化するためのプロジェクトにより、Hiveの実行速度は他のSQLエンジンに負けないぐらい改善されました。

これらの最適化を有効にするためにはちょっとした設定が必要です。この記事では最近のStingerプロジェクトにまつわる、Hiveを高速化するための最適化方法を紹介します。

※ この記事ではHiveのバージョンは0.14以降を想定しています。

# 1. Hive on Tezを使う

TezはこれまでのMapReduceを置き換える高速な実行エンジンです。MapReduceの処理は、前のステージのReduceと次のステージのMapの間で、HDFSへの書き込みが必ず発生します。Tezは前のステージの実行結果をそのまま次のステージに渡すことで、オーバーヘッドを減らし処理速度を改善しています。

TezはApacheのトッププロジェクトになっており、Hadoopのディストリビューションの中では現状Hortonworksのみがサポートしています。セットアップ方法についてはApacheまたはHortonworksのドキュメントを参照してください。

一旦Tezをセットアップした後は、Hive on Tezを利用するのはとても簡単です。Hiveのクエリを実行する前に以下のパラメータを有効にするだけです。

    set hive.execution.engine=tez;


# 2. ORCファイルを使う

ORCファイルはHiveの処理に最適化された列指向のファイルフォーマットです。HiveのテーブルデータをORCファイルにするだけで様々な最適化が行われ、クエリの実行速度を大幅に改善することができます。

また、ORCは列指向ファイルフォーマット（同じ種類のデータで構成）なので圧縮効率が非常に高く、データ量の削減にもつながります。zlibとsnappyなどがサポートされています。（非圧縮も可能）

HiveでORCファイルを使うには、まずORC形式で保存するためのテーブルを作成します。作り方はCREATE TABLE時のSTORED句にORCを指定するだけです。以下はsnappy圧縮のORCテーブルを作成しています。

    CREATE TABLE table_orc(
        customerID int, name string, age int
    ) STORED AS ORC tblproperties("orc.compress"="SNAPPY");

次に既存のTEXTフォーマットなどで保存されているテーブルから、INSERT INTO TABLE文で今作ったORCテーブルにINSERTします。

    INSERT INTO TABLE table_orc SELECT * FROM table_text;

# 3. Vectorizationを使う

Hiveの実行エンジンはデフォルトで一度に一行ずつレコードを処理しています。VectorizationはHive-0.13から導入された最適化手法の一つで、一度に複数行のレコードを処理することでクエリの実行速度を改善します。

Vectorizationはすべてのクエリに適用できるわけではありません。クエリの中で利用しているUDFの種類やWHERE句の書き方などにより、適用できたりできなかったりします。

ただし、今でもコミュニティで開発が行われており、Hiveのバージョンアップごとに適用できるクエリの種類も増えています。

Vectorizationを有効にするのはとても簡単です。クエリの実行時に次のパラメータを有効にするだけです。Vectorizationが使えない場合はこの設定は無視されるだけなので、とりあえずtrueにしておくと良いと思います。

    set hive.vectorized.execution.enabled=true;
    set hive.vectorized.execution.reduce.enabled=true;

# 4. CBOを使う

CBO(Cost Based Optimizer )とはデータの統計情報を使ってクエリの実行計画を改善する最適化手法です。HiveのCBOではApache Calciteというデータ管理のフレームワークを用いて実行計画を生成しています。

まずANALYZEコマンドでCBOを使いたいテーブルの統計情報を取得します。

    -- テーブルの統計情報を取得
    ANALYZE TABLE table_cbo COMPUTE STATISTICS;
    -- カラムの統計情報を取得
    ANALYZE TABLE table_cbo COMPUTE STATISTICS FOR COLUMNS;

取得した統計情報は

    DESC EXTENDED <table名>

を実行したときに表示されるテーブル情報の中のparametersの項目で確認することができます。

    ... parameters:{totalSize=5436635, rawDataSize=123844636, numRows=144000, COLUMN_STATS_ACCURATE=true, numFiles=1, transient_lastDdlTime=1450850103}, ...

※統計情報はANALYZEコマンドを実行した時点の統計情報となります。テーブルのデータが頻繁に更新される場合は定期的に統計情報を更新する必要があります。

次に以下のパラメータを有効にします。

    set hive.cbo.enable=true;
    set hive.compute.query.using.stats=true;
    set hive.stats.fetch.column.stats=true;
    set hive.stats.fetch.partition.stats=true;

これで準備完了です。クエリを実行するとテーブルの統計情報を用いてApache Calsiteが最適な実行計画を生成してくれます。クエリの実行計画はEXPLAINコマンドで確認することができます。

    EXPLAIN EXTENDED <HiveQL>;

hive.cbo.enableをtrueにした場合とfalseにした場合で比べると、実行計画が最適化されていることを確認できます。

# まとめ

Hiveの実行を高速にする最適化の具体的な使い方を紹介しました。非常に簡単な設定で最適化を有効にすることができました。ここで紹介した機能は現在も開発が行われており、バージョンアップごとに更なる改善が期待できます。

オライリーの「プログラミングHive」が発売されてから現在まで２年半ほど経ちますが、この記事で紹介した最適化はその間に開発されたものです。日本語の資料はほとんどないため、社内にHiveに詳しい人がいないとあまり使われていないかもしれません。この記事がHiveのエンジニアやアナリストの参考になってクエリの高速化につながれば幸いです。