はじめに
Apache DrillはスキーマフリーのSQLクエリエンジンです。
Apache Drillがどのぐらいの性能が出るのか軽く測定してみたので、測定内容と活用シーンに関する所感をご紹介します。
Apache Drillとは
端的に言えば、HDFS上のファイル(CSV・JSON)やNoSQL(HBase・MongoDB)等に対してSQLを発行できるものです。
特徴としては、非構造化データに対して直接クエリを発行できること、クエリはANSI SQL準拠であることが挙げられます。
詳しくは公式ドキュメントを参照してみてください。
やってみたこと
- DrillでCSVファイルに対してSQLを実行したときの性能を測定する。
- 比較対象として同じデータをMariaDBにも投入し、同じSQLを実行したときの性能も測定する。
環境
ローカルPC内にVirtualBoxを導入し、仮想マシンを2台立てて測定しました。
ローカルPCのスペックは以下の通りです。
- CPU:Core i7-6500U CPU @ 2.50GHz 2.59GHz
- MEM:16GB
各仮想マシンのリソース割り当ては以下の通りです。
- CPU:2CPU / アクセラレーション有効化
- MEM:6144MB
Drillの導入手順については詳しくご紹介されているサイトがいくつかありました1ので、ここでは概要のみの記載とし、詳細は割愛させていただきます。
仮想サーバ(1):Drill
MapR社がDrillインストール済みの仮想アプライアンスを提供していますので、こちらを利用します。
https://mapr.com/products/mapr-sandbox-hadoop/download-sandbox-drill/
ファイル名:MapR-Sandbox-For-Apache-Drill-1.10.0-5.2.2.ova
をダウンロードして、VirtualBoxへ「仮想アプライアンスのインポート」を行います。
仮想サーバ(2):MariaDB
VirtualBoxより仮想マシンを新規作成し、CentOS7の媒体をマウントしてインストールします。
OS起動後はyumでMariaDBをインストールします。
バージョンは5.5.56を利用します。
テストデータ
CSVファイル
CSVファイルを2つ用意しました。
-
CSVファイルその1:「neko.csv」
- id:1以上のユニークな数値
- name(名前):ランダムな文字列
- age(年齢):1~100までのランダムな数値
- personality_code(性格コード):1~10のランダムな数値
データのイメージは以下の通りです。
id | name | age | personality_code |
---|---|---|---|
1 | e7b261369b | 28 | 3 |
2 | 6f12edf39a | 21 | 5 |
3 | 83f5eb38dc | 42 | 8 |
4 | 792bba127b | 34 | 9 |
5 | 46f48bd851 | 80 | 2 |
6 | 75e3dbb099 | 15 | 4 |
7 | 715e2cbfb0 | 44 | 1 |
8 | 748522d354 | 86 | 3 |
9 | b745f04675 | 9 | 10 |
10 | 50c5abb95e | 32 | 3 |
: | : | : | : |
上記のようなデータを20,480,000レコード用意しました。
- CSVファイルその2:「personality.csv」 ※JOIN用のデータです
- code(性格コード):1~10
- personality(性格):コード値の説明
データのイメージは以下の通りです。
code | personality |
---|---|
1 | friendly |
2 | curious |
3 | gracious |
4 | easygoing |
5 | brave |
6 | ambitious |
7 | funny |
8 | odd |
9 | shy |
10 | violent |
こちらは上記の10レコードのみです。
CSVファイルを作成したら、仮想サーバ(1) のHDFSにPUTしておきます。
> hadoop fs -put neko.csv personality.csv /data
> hadoop fs -ls /data
Found 8 items
-rw-r--r-- 1 mapr mapr 1034773 2017-08-03 16:46 /data/customers.all.csv
drwxr-xr-x - mapr mapr 1 2017-08-03 16:46 /data/flat
-rwxr-xr-x 1 mapr mapr 502719458 2017-12-13 04:51 /data/neko.csv
drwxr-xr-x - mapr mapr 1 2017-08-03 16:46 /data/nested
drwxr-xr-x - mapr mapr 10 2017-08-03 16:46 /data/orders
-rwxr-xr-x 1 mapr mapr 112 2017-12-13 04:51 /data/personality.csv
drwxr-xr-x - mapr mapr 1 2017-08-03 16:46 /data/products
drwxr-xr-x - mapr mapr 0 2017-08-03 16:46 /data/views
MariaDBスキーマ
上記のCSVファイルに倣って、仮想サーバ(2) のMariaDBにテーブルを作成します。
テーブル定義は以下の通りで、特にインデックスは張っていません。
+------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| personality_code | int(11) | YES | | NULL | |
+------------------+--------------+------+-----+---------+----------------+
+-------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+-------+
| code | int(11) | NO | PRI | NULL | |
| personality | varchar(255) | YES | | NULL | |
+-------------+--------------+------+-----+---------+-------+
テーブル作成が完了したら、CSVファイルからデータをINSERTしておきます。
クエリ
今回は、以下の5パターンのSELECTクエリを実行してみました。
- COUNT
- LIKE
- JOIN
- GROUP BY
- ORDER BY
具体的なSQL文は以下の通りです。
COUNT
- Drillの場合
テーブル名に相当する部分は、HDFS上のファイルパスをバッククォートで囲った形式で記述します。
SELECT COUNT(*) FROM `/data/neko.csv`;
- MariaDBの場合
SELECT COUNT(*) FROM neko;
LIKE
- Drillの場合
SELECT * FROM `/data/neko.csv` WHERE `/data/neko.csv`.name LIKE '%abcd%';
- MariaDBの場合
SELECT * FROM neko WHERE name LIKE '%abcd%';
JOIN
- Drillの場合
SELECT *
FROM `/data/neko.csv`
LEFT JOIN `/data/personality.csv`
ON `/data/neko.csv`.personality_code=`/data/personality.csv`.code
WHERE `/data/neko.csv`.age=35;
毎度ファイルパスを記述するのが面倒な場合は、別名記法もいけます
SELECT *
FROM `/data/neko.csv` AS neko
LEFT JOIN `/data/personality.csv` AS per
ON neko.personality_code=per.code
WHERE neko.age=35;
- MariaDBの場合
SELECT *
FROM neko
LEFT JOIN personality
ON neko.personality_code=personality.code
WHERE age=35;
GROUP BY
- Drillの場合
SELECT COUNT(*)
FROM `/data/neko.csv`
WHERE `/data/neko.csv`.age=50
GROUP BY `/data/neko.csv`.personality_code;
- MariaDBの場合
SELECT COUNT(*)
FROM neko
WHERE age=50
GROUP BY personality_code;
ORDER BY
- Drillの場合
データはテキスト型として扱われるため、数値型にキャストしてあげないと正しくソートがされないので要注意です。
SELECT *
FROM `/data/neko.csv`
WHERE age=20
ORDER BY CAST(`/data/neko.csv`.personality_code AS INT);
- MariaDBの場合
SELECT *
FROM neko
WHERE age=20
ORDER BY personality_code;
性能測定
測定条件
- 特に負荷のかかっていない状態で単発のクエリを発行します。
- SQLコンソール(Drillであればsqlline、MariaDBであればmysql)上でクエリを実行し、結果表示されるレスポンスタイムを測定数値として採用します。
- WHERE句の条件を微妙に変えつつ、5回実行した結果の平均値を採用しています。
- 今回の計測では飛び抜けた値(外れ値)は見られませんでした。
測定結果
数値の単位はsecです。
クエリ | Drill | MariaDB |
---|---|---|
COUNT | 3.97 | 3.19 |
LIKE | 6.77 | 7.83 |
JOIN | 14.17 | 5.62 |
GROUP BY | 4.59 | 4.74 |
ORDER BY | 17.26 | 6.81 |
JOINやORDER BYが苦手なようですが、全般的にMariaDBと比較して劇的に遅いという訳でもなさそうです。
無論、MariaDBはインデックスを張っていないので、さらに高速化できる余地は残しています。
とは言え、HDFSに置いただけのテキストファイルにいきなりSQLを投げて、チューニングしていないRDBとほぼ遜色ない性能が出る、となると魅力的に感じます。
所感
あらかじめデータ構造や発行するクエリが決まっているようなシーンであれば、やはりRDBの方に分があります。
Drillの使いどころとしては、日々増大していく非構造化データに対してアドホックにクエリを投げたい(多少は時間がかかってもいい)、というケースで力を発揮できるだろうと思いました。
-
以下の記事を大変参考にさせていただきました。
Apache Drill を使ってみよう!!
http://azure.sios.jp/archives/jtp-apachedrill-20170308 ↩