この記事はMicroAd Advent Calendar 2019の10日目の記事です。
はじめに
MySQLなどのクエリで集合差を表現する方法にNOT EXISTS
があります。NOT IN
を使うよりはマシですが、この処理のパフォーマンスが気になる場面があり、以下の記事にあるようなLEFT OUTER JOIN
を使う方法を知りました。
参考:MySQLで集合差を出す
例えば、NOT EXISTS
を含む次のような「ブラックリストに入っていないメンバーの情報を取得する」クエリ
SELECT
id
,name
FROM
member
WHERE NOT EXISTS (
SELECT
id
FROM
black_list
WHERE
member.id = black_list.id
LIMIT 1
)
を
SELECT
id
,name
FROM
member
LEFT OUTER JOIN black_list
ON member.id = black_list.id
WHERE
black_list.id IS NULL
のように表現することができ、MySQLではこちらの方が高速であるケースが多いようです。
業務でHiveを使うことがあり、Hiveの場合はパフォーマンスにどの程度差が出るのかを簡単に調べてみました。
検証
Hive上の2つのテーブルtable1
とtable2
を用いて、2つの記法の所要時間を比較しました。レコード数は1億5000万件ほど用意し、集合差の大きさによる所要時間の違いも検証しました。
- 集合差0:
table1
,table2
が完全一致で、集合差が0 - 集合差10%:
table2
にはtable1
のレコードの10%だけが入っている - 集合差50%:
table2
にはtable1
のレコードの半分が入っている - 集合差90%:
table2
にはtable1
のレコードの90%が入っている - 集合差100%:
table2
が空で、集合差がtable1
と完全一致
なお、CDHのバージョンは5.14
で、テーブルの圧縮形式はParquet
です。
NOT EXISTS
を使う場合
SELECT
id
FROM table1
WHERE NOT EXISTS (
SELECT
id
FROM table2
WHERE table1.id = table2.id
)
- 集合差0: 97 (sec)
- 集合差10%: 97 (sec)
- 集合差50%: 99 (sec)
- 集合差90%: 100 (sec)
- 集合差100%: 97 (sec)
LEFT OUTER JOIN
を使う場合
SELECT
id
FROM table1
LEFT OUTER JOIN table2
ON table1.id = table2.id
WHERE table2.id IS NULL
- 集合差0: 99 (sec)
- 集合差10%: 96 (sec)
- 集合差50%: 101 (sec)
- 集合差90%: 100 (sec)
- 集合差100%: 98 (sec)
結果
今回の検証では、この2つの記法と集合差の大きさによるパフォーマンスに明確な差は見られませんでした。
NOT EXISTS
はあまり速くないというイメージがありましたが、意外とそんなことはないのかもしれません。
おわりに
HiveでのNOT EXISTS
と、その代わりにLEFT OUTER JOIN
を使った場合とのパフォーマンスを、簡易的ではありますが比較しました。
何らかの参考になれば幸いです。
より良い記法や検証方法などがありましたら、ご指摘いただけますと有難いです。