MDSのHeatWave機能を使ってみた

こんにちは。Oracle Cloud Infrastructure(OCI)特集 編集部です。

以前にMySQL Database Service (MDS)を使用したブログを記載していました。
MySQL Database Service (MDS)を使ってみた

そのMDSにおいて、HeatWaveという機能を有効化すると
SQLクエリを高速化できるとの事で、
今回はそのHeatWave機能を実際に使ってみたいと思います。

また、HeatWaveを使用するには条件もあるみたいです。
・HeatWaveを使用可能なMDSのシェイプはあらかじめ決まっている
 ※現状では
  ・BM.Standard.E2.64
  ・MySQL.HeatWave.VM.Standard.E3
・サポートされていないデータ型がある
 ※その型を除外してロードすることは可能

■参考サイト
・HeatWaveチュートリアル
https://oracle-japan.github.io/ocitutorials/beginners/creating-HeatWave/

・OCIマニュアル(英語)
https://docs.oracle.com/en-us/iaas/mysql-database/doc/heatwave1.html
⇒大まかな内容のため、詳細は下記を参照

・HeatWaveユーザガイド(英語)
https://dev.mysql.com/doc/heatwave/en/
⇒詳細な使用方法はこちらに記載されています


■今回の作業の流れ
・前準備
・1.HeatWave機能の有効化
・2.HeatWave使用準備
・3.検証

前準備

まずはMDSをシェイプ「MySQL.HeatWave.VM.Standard.E3」で作成します。
※MDSの作成方法は以前のブログを参照ください。
 MySQL Database Service (MDS)を使ってみた

今回のHeatWaveの検証にあたり、DBのデータ量は多めに用意しようと思いました。
そこで、色々探したところAWSのオープンデータに
大量のテキストデータが存在したため、こちらを使ってみます。
https://registry.opendata.aws/gdelt/
⇒世界各国で発生したイベントのデータベース情報のようです。

AWS CLIを使用してテキストデータをダウンロードし、
“LOAD DATA LOCAL INFILE ~” 文でMDSへ下記のように取り込みました。

データベース名:test_db
テーブル名:test_table
※テーブルの実サイズは 約226GBレコード数は5億9千万ぐらいでした

 

1.HeatWave機能の有効化

まずはMDSに対して HeatWave機能の有効化を行うにあたり、
OCI Webコンソールにログインし、
HeatWave機能を有効にしたいMDSの画面を開きます。

画面左下の「HeatWave」をクリックし、
画面右側の「HeatWaveクラスタの追加」を押下します。
※画面に記載の通り、MDSのシェイプは「MySQL.HeatWave.VM.Standard.E3」です



「ノード数」の箇所でSQLクエリを並列実行するサーバ数(HeatWaveクラスタノード数)を
入力するのですが、まずは「ノード数の見積り」ボタンを押下します。



「見積りの生成」を押下します。

MDS上の実際のデータが読み込まれて表示されるようです。
「∨」をクリックします。
※MDS上に作成した データベース(test_db)とテーブル(test_table)が表示されています。


SQLを高速化したいテーブルにチェックを入れます。
そうすると画面下側にて HeatWaveクラスタノード数が自動的に決定されるため、
この状態で「ノード数見積りの適用」を押下します。


ノード数の情報が追加されています。
この状態で「HeatWaveクラスタの追加」を押下します。


HeatWaveノードの追加が開始されます。


追加が完了すると「アクティブ」と表示されます。
※完了まで約10分でした



2.HeatWave使用準備

mysqlコマンドにてMDSへ接続します。
下記コマンドでHeatWaveが有効であることを確認します。
(「Value」が「ONLINE」であれば有効のようです)

mysql> SHOW STATUS LIKE 'rapid_service_status';
+----------------------+--------+
| Variable_name        | Value  |
+----------------------+--------+
| rapid_service_status | ONLINE |
+----------------------+--------+
1 row in set (0.01 sec)

mysql>


SQLクエリを高速化したいテーブルに対し、HeatWave (RAPID)を有効にする定義を行います。

mysql> alter table test_db.test_table secondary_engine=rapid;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql>

 

テーブルデータをHeatWaveクラスタへ読み込みます。
完了までに13分55秒かかっていました。
※テーブルサイズは約226GBのため、単純計算ですが
 277MBytes/secぐらいでデータをロードしている感じですかね。

mysql> alter table test_db.test_table secondary_load;
Query OK, 0 rows affected (13 min 54.45 sec)

mysql>
 
 

3.検証

まずはテーブル情報を記載します。

mysql> desc test_table;
+-----------------------+-------------+------+-----+---------+----------------+
| Field                 | Type        | Null | Key | Default | Extra          |
+-----------------------+-------------+------+-----+---------+----------------+
| id                    | int         | NO   | PRI | NULL    | auto_increment |
| GLOBALEVENTID         | int         | YES  |     | NULL    |                |
| SQLDATE               | int         | YES  |     | NULL    |                |
| MonthYear             | int         | YES  |     | NULL    |                |
| Year                  | int         | YES  |     | NULL    |                |
| FractionDate          | varchar(30) | YES  |     | NULL    |                |
| Actor1Code            | varchar(30) | YES  |     | NULL    |                |
| Actor1Name            | text        | YES  |     | NULL    |                |
| Actor1CountryCode     | varchar(30) | YES  |     | NULL    |                |
| Actor1KnownGroupCode  | varchar(30) | YES  |     | NULL    |                |
| Actor1EthnicCode      | varchar(30) | YES  |     | NULL    |                |
| Actor1Religion1Code   | varchar(30) | YES  |     | NULL    |                |
| Actor1Religion2Code   | varchar(30) | YES  |     | NULL    |                |
| Actor1Type1Code       | varchar(30) | YES  |     | NULL    |                |
| Actor1Type2Code       | varchar(30) | YES  |     | NULL    |                |
| Actor1Type3Code       | varchar(30) | YES  |     | NULL    |                |
| Actor2Code            | varchar(30) | YES  |     | NULL    |                |
| Actor2Name            | text        | YES  |     | NULL    |                |
| Actor2CountryCode     | varchar(30) | YES  |     | NULL    |                |
| Actor2KnownGroupCode  | varchar(30) | YES  |     | NULL    |                |
| Actor2EthnicCode      | varchar(30) | YES  |     | NULL    |                |
| Actor2Religion1Code   | varchar(30) | YES  |     | NULL    |                |
| Actor2Religion2Code   | varchar(30) | YES  |     | NULL    |                |
| Actor2Type1Code       | varchar(30) | YES  |     | NULL    |                |
| Actor2Type2Code       | varchar(30) | YES  |     | NULL    |                |
| Actor2Type3Code       | varchar(30) | YES  |     | NULL    |                |
| IsRootEvent           | int         | YES  |     | NULL    |                |
| EventCode             | int         | YES  |     | NULL    |                |
| EventBaseCode         | int         | YES  |     | NULL    |                |
| EventRootCode         | int         | YES  |     | NULL    |                |
| QuadClass             | int         | YES  |     | NULL    |                |
| GoldsteinScale        | varchar(30) | YES  |     | NULL    |                |
| NumMentions           | int         | YES  |     | NULL    |                |
| NumSources            | int         | YES  |     | NULL    |                |
| NumArticles           | int         | YES  |     | NULL    |                |
| AvgTone               | varchar(30) | YES  |     | NULL    |                |
| Actor1Geo_Type        | int         | YES  |     | NULL    |                |
| Actor1Geo_FullName    | text        | YES  |     | NULL    |                |
| Actor1Geo_CountryCode | varchar(30) | YES  |     | NULL    |                |
| Actor1Geo_ADM1Code    | varchar(30) | YES  |     | NULL    |                |
| Actor1Geo_Lat         | varchar(30) | YES  |     | NULL    |                |
| Actor1Geo_Long        | varchar(30) | YES  |     | NULL    |                |
| Actor1Geo_FeatureID   | varchar(30) | YES  |     | NULL    |                |
| Actor2Geo_Type        | int         | YES  |     | NULL    |                |
| Actor2Geo_FullName    | text        | YES  |     | NULL    |                |
| Actor2Geo_CountryCode | varchar(30) | YES  |     | NULL    |                |
| Actor2Geo_ADM1Code    | varchar(30) | YES  |     | NULL    |                |
| Actor2Geo_Lat         | varchar(30) | YES  |     | NULL    |                |
| Actor2Geo_Long        | varchar(30) | YES  |     | NULL    |                |
| Actor2Geo_FeatureID   | varchar(30) | YES  |     | NULL    |                |
| ActionGeo_Type        | int         | YES  |     | NULL    |                |
| ActionGeo_FullName    | text        | YES  |     | NULL    |                |
| ActionGeo_CountryCode | varchar(30) | YES  |     | NULL    |                |
| ActionGeo_ADM1Code    | varchar(30) | YES  |     | NULL    |                |
| ActionGeo_Lat         | varchar(30) | YES  |     | NULL    |                |
| ActionGeo_Long        | varchar(30) | YES  |     | NULL    |                |
| ActionGeo_FeatureID   | varchar(30) | YES  |     | NULL    |                |
| DATEADDED             | int         | YES  |     | NULL    |                |
| SOURCEURL             | text        | YES  |     | NULL    |                |
+-----------------------+-------------+------+-----+---------+----------------+
59 rows in set (0.00 sec)
 
テーブルのレコード数はおおよそ5億件以上、サイズが226GBであることを下記で示しています。

mysql> SELECT table_name, table_rows , floor(data_length/1024/1024/1024) AS table_GB, floor(index_length/1024/1024/1024) AS index_GB
    -> FROM  information_schema.tables WHERE table_schema='test_db';
+------------+------------+----------+----------+
| TABLE_NAME | TABLE_ROWS | table_GB | index_GB |
+------------+------------+----------+----------+
| test_table |  560800929 |      226 |        0 |
+------------+------------+----------+----------+
1 row in set (0.00 sec)

mysql>


 

HeatWave無し/有りでの処理速度を比較するにあたり、
次のようにselect文を実行してみました。
・テーブル内を全検索するようなselect文(select count(Year) from test_table;)と
 where句で条件をちょっと絞ったselect文(select count(Year) from test_table where Year=2015;)
 を実行。「Year」列はint型で西暦が入っています。「2015」は適当です。
 (後者のselect文はインデックスも作っていないため、結果的にフルスキャンですが…)
・select文の実行の前にexplainで実行計画を確認しています。
 explainにて「type」が「ALL」である事からテーブルのフルスキャンを確認できます。

まずはHeatWaveが無効の状態の結果を記載します。
それぞれの結果は 24分以上かかっていました…。

mysql> explain select count(Year) from test_table;
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows      | filtered | Extra |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------+
|  1 | SIMPLE      | test_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 560800929 |   100.00 | NULL  |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql>
mysql>
mysql> select count(Year) from test_table;
+-------------+
| count(Year) |
+-------------+
|   596867240 |
+-------------+
1 row in set (24 min 24.54 sec)

mysql>
mysql>
mysql> explain select count(Year) from test_table where Year=2015;
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows      | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------------+
|  1 | SIMPLE      | test_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 560800929 |    10.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------------+
1 row in set, 1 warning (0.04 sec)

mysql>
mysql>
mysql> select count(Year) from test_table where Year=2015;
+-------------+
| count(Year) |
+-------------+
|    66282411 |
+-------------+
1 row in set (24 min 24.53 sec)

mysql>
 

次に、HeatWaveが有効の状態の結果です。
explainにて、この時も「type」が「ALL」である事からフルスキャンかと思いますが、
extra」が「Using secondary engine RAPID」と表示されていることからHeatWaveを使用する事となります。
そして、それぞれの結果は1秒未満で返ってきています。
速すぎですね…。

mysql> explain select count(Year) from test_table;
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+------------------------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows      | filtered | Extra                        |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+------------------------------+
|  1 | SIMPLE      | test_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 560800929 |   100.00 | Using secondary engine RAPID |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql>
mysql>
mysql>
mysql> select count(Year) from test_table;
+-------------+
| count(Year) |
+-------------+
|   596867240 |
+-------------+
1 row in set (0.18 sec)

mysql>
mysql> explain select count(Year) from test_table where Year=2015;
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------------------------------------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows      | filtered | Extra                                     |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------------------------------------------+
|  1 | SIMPLE      | test_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 560800929 |    10.00 | Using where; Using secondary engine RAPID |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql>
mysql>
mysql>
mysql> select count(Year) from test_table where Year=2015;
+-------------+
| count(Year) |
+-------------+
|    66282411 |
+-------------+
1 row in set (0.32 sec)

mysql>


HeatWaveが有効な状態で、「Year」列の西暦を「2015」から
2016」や「2015~2017」に変更してみたりしましたが、
すべて1秒未満で返ってきました。速いです。

mysql> select count(Year) from test_table where Year=2016;
+-------------+
| count(Year) |
+-------------+
|    73269882 |
+-------------+
1 row in set (0.19 sec)

mysql>
mysql> select count(Year) from test_table where Year between 2015 and 2017;
+-------------+
| count(Year) |
+-------------+
|   205821688 |
+-------------+
1 row in set (0.38 sec)

mysql>



ここで一旦、HeatWaveクラスタを停止してみます。

「停止」を押下します。


状態が「非アクティブ」と表示されていることを確認します。


停止後に再度SQLを実行すると HeatWaveが無効の時と同じで
24分以上かかっていました。

mysql> explain select count(Year) from test_table;
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows      | filtered | Extra |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------+
|  1 | SIMPLE      | test_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 560800929 |   100.00 | NULL  |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql>
mysql> select count(Year) from test_table;
+-------------+
| count(Year) |
+-------------+
|   596867240 |
+-------------+
1 row in set (24 min 22.65 sec)

mysql>
mysql>
mysql> explain select count(Year) from test_table where Year=2015;
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows      | filtered | Extra       |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------------+
|  1 | SIMPLE      | test_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 560800929 |    10.00 | Using where |
+----+-------------+------------+------------+------+---------------+------+---------+------+-----------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql>
mysql>
mysql> select count(Year) from test_table where Year=2015;
+-------------+
| count(Year) |
+-------------+
|    66282411 |
+-------------+
1 row in set (24 min 24.57 sec)

mysql>

 

まとめ

シェイプは「MySQL.HeatWave.VM.Standard.E3」を選択し、
高速化したいテーブルを HeatWaveクラスタへ読み込ませる操作は必要ですが
その他に特別な作業を行わず、SQLクエリがかなり速くなりました!
SQLクエリがどうにも遅くて困っている…という方々には是非使用してほしい機能ですね。

弊社では「MDS/HeatWave」の導入支援を行っておりますので
ご要望・ご相談などございましたらご連絡ください。

▽MySQL Database Service(MDS) / HeatWave導入支援サービス
https://www.techvan.co.jp/solution/it_infra/cloudinfra/mysql_database_service_heatwave/