[Oracle Cloud] 読み込みが超高速になる HeatWave を触ってみた

# はじめに

MySQL Database Service (略して MDS) に、HeatWave 機能がリリースされました！HeatWave は、MySQL の読み込みワークロードの超高速化が出来て、大量のデータ分析・時間の掛かる読み込みSQLクエリーの速度を向上できます。OCI コンソール画面で、MySQL Database Service に HeatWave 機能チェックボックスを ON にするだけで使えるので、既存のアプリケーションに手を加える必要がないのも魅力的です。アプリケーション側は何も手を加えず、HeatWave を有効にするだけで読み込みワークロードが高速化されます。

今回の記事では、MySQL Database Service と HeatWave の新規作成手順を紹介します。



# Service Limit

Service Limit の関係で、HeatWave はデフォルトだと使えない状態です。まずは Service Limit を上げる申請をしていきます。

![1608799627973.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/618130ff-f675-2d18-2fab-5eccf81372cf.png)



MySQL のプルダウンを選択して表示される画面のうち、次の2個が HeatWave に関係するものです。Service Limit が 0 になっているので、画面上部の request a service limit ... から上限緩和申請をします。

```
MySQL Analytics VM.Standard.E3 Nodes Count : HeatWave Node
MySQL Database for Analytics VM.Standard.E3 Nodes Count : MySQL本体
```

![1608799696709.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/ace14ebd-a9a2-53f1-b754-bb3340b0c48a.png)



忘れずに次の2種類を申請していきます。`MySQL Analytics VM.Standard.E3 Nodes Count` は、HeatWave 用の Node で最低2以上必要です。`MySQL Database for Analytics VM.Standard.E3 Nodes Count` は、MySQL 本体なので、1以上が必要です。適当にこんな感じに理由を書いていきましょう (たぶん日本語でも大丈夫だと思います)

HeatWave 用 Node は、1Node あたり約400GB ほどのデータを格納できます。HeatWave にオフロードしたいデータ容量に合わせて、申請する Node 数を調整してみましょう。

```
HeatWave の動作検証をしたいため、上限緩和申請を致します。
MySQL Analytics VM.Standard.E3 Nodes Count : 3 Node
MySQL Database for Analytics VM.Standard.E3 Nodes Count : 1 Node
```

![1608800082629.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/14a2eecb-f82d-a243-84d8-66bf2bbffc52.png)



承認されたあとは、このように Service Limit が増えています

![1608798186531.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/db58fe67-70dc-f068-3fbb-c3089116d35c.png)



# MySQL Database Service 作成

Service Limit の上限緩和後、MySQL Database Service + HeatWave を作成していきます。MySQL から DB Systems を選びます。

![1608798271540.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/deb4fa22-950f-3e18-f290-c8b8187ec646.png)



Create MySQL DB System を選びます

![1608798313088.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/08f3fb04-dacd-76fc-c249-b5cc95d245b4.png)



適当に Name や Description を入れた後に、Change Shape を押します。

![1608798402889.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/c3ef571a-33a9-3f5c-26bc-baec0f9fd088.png)



HeatWave が使える Shape を選択します。現状、E3 の Shape は、`MySQL.Analytics.VM.Standard.E3`  のみ HeatWave を有効にできます。

![1608798446907.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/f9a7ea01-8c4c-7aed-709d-7e93ceca8a8c.png)



ストレージ容量を入力します。

![1608798504806.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/a8facfcb-1a5f-7740-d9ef-a4d2d37f8fa3.png)



各種パラメータを入れて、Next をいれます

![1608798590545.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/4cae2c77-75af-322a-12b5-5a76e1787c1e.png)



Create を押して、MySQL Database Service を作成します。

![1608798619559.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/3affc1ff-6feb-8ced-9ffd-687ed94ea9b9.png)



Creating となっています。自分の環境では、Active まで 10分弱ほど掛かりました。

![1608798726537.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/31336c1e-801f-3454-1ff8-d714dec856a4.png)



ACTIVE になりました。MySQL Database Service に、HeatWave を追加していきます。左下のメニューから、HeatWave を選択します。

![1608800265314.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/99906475-d21e-deea-c972-35bfd8879660.png)



Add HeatWave Cluster を押します。

![1608800299746.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/1d9bab2e-c90c-1e12-2fb8-16c0b7151121.png)



Shape が `MySQL.Analytics.VM.Standard.E3` なことを確認し、Node Count を必要分いれたあとに、Add Heatwave Cluster を選びます。HeatWave 1Node あたり、約400GBのデータを格納できるといわれています。

![1608800418294.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/47345474-a9e0-a41c-4647-c82aad9a7ded.png)



Creating になります。HeatWave を 3 Node で選択したので、HeatWave Nodes が 3行 Creating となっているのが見えます。

![1608800511490.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/743baa58-0d87-7582-c21a-62b4d7b53d39.png)



10分弱ほどで HeatWave Cluster が有効になります

![1608808042395.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/3120d42c-0edf-92f4-f71a-8ff7eba60a4c.png)



# 1億行のテストデータ作成

これで、MySQL Database Service に HeatWave 機能を追加できました。1億行のサンプルデータを作っていくために、OCI Compute Instance に MySQL Client をインストールして接続していきます。

MySQL Repository を有効化

```
sudo yum install https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
```



MySQL Client をインストール

```
sudo yum install mysql-community-client
```



memo : 依存関係

```
========================================================================================================================
 Package                                   Arch              Version                 Repository                    Size
========================================================================================================================
Installing:
 mysql-community-client                    x86_64            8.0.22-1.el7            mysql80-community             48 M
 mysql-community-libs                      x86_64            8.0.22-1.el7            mysql80-community            4.6 M
     replacing  mariadb-libs.x86_64 1:5.5.68-1.el7
 mysql-community-libs-compat               x86_64            8.0.22-1.el7            mysql80-community            1.2 M
     replacing  mariadb-libs.x86_64 1:5.5.68-1.el7
Installing for dependencies:
 mysql-community-client-plugins            x86_64            8.0.22-1.el7            mysql80-community            235 k
 mysql-community-common                    x86_64            8.0.22-1.el7            mysql80-community            616 k

Transaction Summary
========================================================================================================================
```



MySQL Database Service の Endpoint を確認します

![1608873718074.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/a3b9038c-a7b4-b6e2-4c1c-8058044432db.png)



MySQL Client から接続します。user名と Password は、MySQL Database Service を新規作成した時に指定したものを入れます。

```
mysql --host heatwave.mysqlsubnet01.vcn.oraclevcn.com -u admin -p
```



ログイン完了

```
[opc@mysql-client01 ~]$ mysql --host heatwave.mysqlsubnet01.vcn.oraclevcn.com -u admin -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 259
Server version: 8.0.22-u4-cloud MySQL Enterprise - Cloud

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```



データベース一覧を確認します。

```
mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.01 sec)

mysql>
```



適当な名前で、データベースを作成します。

```
CREATE DATABASE sugi01;
```



確認

```
mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sugi01             |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql>
```



作成した sugi01 データベースに切り替えます。

```
mysql> USE sugi01;
Database changed
mysql>
```



Table は何もありません

```
mysql> SHOW TABLES;
Empty set (0.00 sec)

mysql>
```



必要な sample table を 10行分作成します。

```
CREATE TABLE sample(
  id INT(11) NOT NULL AUTO_INCREMENT,
  value INT(5) NOT NULL DEFAULT 0,
  PRIMARY KEY (id)
);

INSERT INTO sample(value)
VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
```



1億行のテストデータを格納するための、account テーブルを作成します。

```
CREATE TABLE account(
  id INT(11) NOT NULL AUTO_INCREMENT,
  name VARCHAR(50) NOT NULL,
  subid INT(11) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);
```



作成した account テーブルに、1億行を生成します。
10行データが入っている sample テーブルを使って、Cross Join(直積) をした上で、account テーブルにテストデータを Insert していきます。
自分の環境では、10分17秒ほど掛かりました。

```
INSERT INTO account(name, subid)
SELECT
  CONCAT('NAME' , @rownum := @rownum + 1),@rownum
FROM
  sample AS s1,
  sample AS s2,
  sample AS s3,
  sample AS s4,
  sample AS s5,
  sample AS s6,
  sample AS s7,
  sample AS s8,
  (SELECT @rownum := 0) AS v;
```



正しくデータが格納されています。

```
mysql> SELECT * FROM account LIMIT 10;
+----+--------+-------+---------------------+---------------------+
| id | name   | subid | created_at          | updated_at          |
+----+--------+-------+---------------------+---------------------+
|  1 | NAME1  |     1 | 2020-12-26 01:53:45 | 2020-12-26 01:53:45 |
|  2 | NAME2  |     2 | 2020-12-26 01:53:45 | 2020-12-26 01:53:45 |
|  3 | NAME3  |     3 | 2020-12-26 01:53:45 | 2020-12-26 01:53:45 |
|  4 | NAME4  |     4 | 2020-12-26 01:53:45 | 2020-12-26 01:53:45 |
|  5 | NAME5  |     5 | 2020-12-26 01:53:45 | 2020-12-26 01:53:45 |
|  6 | NAME6  |     6 | 2020-12-26 01:53:45 | 2020-12-26 01:53:45 |
|  7 | NAME7  |     7 | 2020-12-26 01:53:45 | 2020-12-26 01:53:45 |
|  8 | NAME8  |     8 | 2020-12-26 01:53:45 | 2020-12-26 01:53:45 |
|  9 | NAME9  |     9 | 2020-12-26 01:53:45 | 2020-12-26 01:53:45 |
| 10 | NAME10 |    10 | 2020-12-26 01:53:45 | 2020-12-26 01:53:45 |
+----+--------+-------+---------------------+---------------------+
10 rows in set (0.00 sec)

mysql>
```



1億行のテストデータが格納されています

```
mysql> SELECT COUNT(id) FROM account;
+-----------+
| COUNT(id) |
+-----------+
| 100000000 |
+-----------+
1 row in set (0.01 sec)

mysql>
```



フルスキャンが発生するようなクエリーを投げてみます。1億件のフルスキャンなので、それなりの時間が掛かります。(具体的な秒数は伏せておきます)

```
mysql> SELECT * FROM account WHERE subid BETWEEN 100 and 110;
+-----+---------+-------+---------------------+---------------------+
| id  | name    | subid | created_at          | updated_at          |
+-----+---------+-------+---------------------+---------------------+
| 100 | NAME100 |   100 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 101 | NAME101 |   101 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 102 | NAME102 |   102 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 103 | NAME103 |   103 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 104 | NAME104 |   104 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 105 | NAME105 |   105 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 106 | NAME106 |   106 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 107 | NAME107 |   107 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 108 | NAME108 |   108 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 109 | NAME109 |   109 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 110 | NAME110 |   110 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
+-----+---------+-------+---------------------+---------------------+
11 rows in set (XX.XX sec)

mysql>
```



この時の実行計画を見てみます。type が ALL となっており、フルスキャンになっています。

```
mysql> EXPLAIN SELECT * FROM account WHERE subid BETWEEN 100 and 110;
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows     | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------+
|  1 | SIMPLE      | account | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 97926422 |    11.11 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql>
```



memo : DROP

```
DROP TABLE account;
```



# HeatWave 同期進捗率表示準備

これから、1億行のデータを HeatWave に同期していきますが、自動的に同期進捗率を取得したいので、簡単な Bash Script を作成します。
SQL で実行すると、HeatWave とのデータ同期進捗率が表示できます。

```
SELECT VARIABLE_VALUE
FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'rapid_load_progress';
```



実行例はこんな感じです。今は何も同期していないので、0% となっています。同期完了になったら、この表示が 100% になります。

```
mysql> SELECT VARIABLE_VALUE
    -> FROM performance_schema.global_status
    -> WHERE VARIABLE_NAME = 'rapid_load_progress';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 0.000000       |
+----------------+
1 row in set (0.00 sec)

mysql>
```



また、同期が完了しているテーブル一覧をSQLで出す事もできます。

```
SELECT NAME, LOAD_STATUS FROM performance_schema.rpd_tables, performance_schema.rpd_table_id WHERE rpd_tables.ID = rpd_table_id.ID;
```



実行例です。今は何も同期していないので、表示は Empty です。

```
mysql> SELECT NAME, LOAD_STATUS FROM performance_schema.rpd_tables, performance_schema.rpd_table_id WHERE rpd_tables.ID = rpd_table_id.ID;
Empty set (0.00 sec)

mysql>
```



一度、MySQL Client から抜けて、HeatWave とのデータ同期進捗率を定期実行するスクリプトを作成していきます。

```
mkdir ~/heatwavetest
```



簡単な Bash Script を作成します。mysql コマンドの接続先やパスワードは環境に合わせて指定します。

```bash
cat <<'EOF' > ~/heatwavetest/GetHeatWaveProgress.sh
#!/bin/bash
while true; do
  echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
  date;
  mysql --host heatwave.mysqlsubnet01.vcn.oraclevcn.com -u admin -p"your password" --execute="SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'rapid_load_progress';";
  echo "          ";
  sleep 10s;
done
EOF
```



実行権限付与

```
chmod +x ~/heatwavetest/GetHeatWaveProgress.sh
```



テスト実行していみます。progress.txt に問題なく進捗率が表示されることを確認します。

```
~/heatwavetest/GetHeatWaveProgress.sh >> ~/heatwavetest/progress.txt
```



バックグラウンド実行をしておきます

```
nohup ~/heatwavetest/GetHeatWaveProgress.sh >> ~/heatwavetest/progress.txt &
```



確認

```
[opc@mysql-client01 ~]$ ps aux | grep heat
opc      12272  0.0  0.0 113256  1308 pts/0    S    12:21   0:00 /bin/bash /home/opc/heatwavetest/GetHeatWaveProgress.sh
opc      12277  0.0  0.0 112780   684 pts/0    S+   12:22   0:00 grep --color=auto heat
[opc@mysql-client01 ~]$
```



# HeatWave 同期開始

HeatWave へ同期を開始する前に、1億行格納されている account テーブルの使用容量を確認します。
容量確認SQL

```
SELECT  
    table_name, engine, table_rows AS tbl_rows,
    avg_row_length AS rlen,  
    floor((data_length+index_length)/1024/1024) AS ALL_MB,  #総容量
    floor((data_length)/1024/1024) AS DATA_MB,  #データ容量
    floor((index_length)/1024/1024) AS Index_MB   #インデックス容量
FROM 
    information_schema.tables  
WHERE
    table_schema=database()  
ORDER BY
    (data_length+index_length) DESC;  
```



実行例
4893 MB使っています。約5GBのテーブルをこれから HeatWave に同期します。

```
+------------+--------+----------+------+--------+---------+----------+
| TABLE_NAME | ENGINE | tbl_rows | rlen | ALL_MB | DATA_MB | Index_MB |
+------------+--------+----------+------+--------+---------+----------+
| account    | InnoDB | 99785933 |   51 |   4893 |    4893 |        0 |
| sample     | InnoDB |       10 | 1638 |      0 |       0 |        0 |
+------------+--------+----------+------+--------+---------+----------+
2 rows in set (0.00 sec)
```



SECONDARY_ENGINE に、HeatWave(RAPID) を使う事の定義をします。おそらく、RAPID 以外の SECONDARY_ENGINE が将来的に出てきたときには、使うエンジンを切り替えられるような意図があるのかなと想像しています。このタイミングでは、まだ同期開始されません。

```
ALTER TABLE account SECONDARY_ENGINE = RAPID;
```



次のコマンドで、実際に同期が開始されます。(同期完了するまでプロンプトが返ってこない)

```
ALTER TABLE account SECONDARY_LOAD;
```



実行例
1億行データ、約5GB のデータでは、約1分38秒ほど同期に時間が掛かりました。

```
mysql> ALTER TABLE account SECONDARY_LOAD;
Query OK, 0 rows affected (1 min 38.30 sec)

mysql>
```



データ同期の進捗率を確認するコマンドです。62% 程の進捗率です。

```
mysql> SELECT VARIABLE_VALUE
    -> FROM performance_schema.global_status
    -> WHERE VARIABLE_NAME = 'rapid_load_progress';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 62.118067      |
+----------------+
1 row in set (0.00 sec)

mysql>
```



テーブル単位でのデータ同期ステータスが分かります。同期中なので、`LOADING_RPDGSTABSTATE` となっています。

```
mysql> SELECT NAME, LOAD_STATUS FROM performance_schema.rpd_tables, performance_schema.rpd_table_id WHERE rpd_tables.ID = rpd_table_id.ID;
+----------------+-----------------------+
| NAME           | LOAD_STATUS           |
+----------------+-----------------------+
| sugi01.account | LOADING_RPDGSTABSTATE |
+----------------+-----------------------+
1 row in set (0.00 sec)

mysql>
```



同期が完了すると、進捗率が 100% になっています。

```
mysql> SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'rapid_load_progress';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 100.000000     |
+----------------+
1 row in set (0.00 sec)

mysql>
```



テーブル単位のステータスは、`AVAIL_RPDGSTABSTATE` となっています。

```
mysql> SELECT NAME, LOAD_STATUS FROM performance_schema.rpd_tables, performance_schema.rpd_table_id WHERE rpd_tables.ID = rpd_table_id.ID;
+----------------+---------------------+
| NAME           | LOAD_STATUS         |
+----------------+---------------------+
| sugi01.account | AVAIL_RPDGSTABSTATE |
+----------------+---------------------+
1 row in set (0.00 sec)

mysql>
```



# HeatWave 実行テスト

同期が完了したので、HeatWave のテストを行います。まずは、EXPLAIN で実行計画を見て行きます。フルスキャンが発生する SQLクエリーを使っています。

```
EXPLAIN SELECT * FROM account WHERE subid BETWEEN 100 and 110;
```



実行例です。type は `ALL` となっているので、テーブルのフルスキャンが発生していますが、Extra の部分で、`Using secondary engine RAPID` が表示されており、HeatWave にオフロードされることがわかります。なお、Hint 句でオフロードの有無をコントロールすることも出来ます。

```
mysql> EXPLAIN SELECT * FROM account WHERE subid BETWEEN 100 and 110;
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------------------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows     | filtered | Extra                                     |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------------------------------------+
|  1 | SIMPLE      | account | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 97926422 |    11.11 | Using where; Using secondary engine RAPID |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql>
```



それでは、実際に 1億行のテーブルをフルスキャンさせて性能を見てみましょう。
0.02 秒で結果が返ってきています。HeatWave 無効時の秒数は伏せていますが、ものすごい早くなっています。
自分の環境では、倍率でいうと約1500倍ほど早くなりました。ぜひみなさんの環境でも試してみてください。

```
mysql> SELECT * FROM account WHERE subid BETWEEN 100 and 110;
+-----+---------+-------+---------------------+---------------------+
| id  | name    | subid | created_at          | updated_at          |
+-----+---------+-------+---------------------+---------------------+
| 109 | NAME109 |   109 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 110 | NAME110 |   110 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 104 | NAME104 |   104 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 100 | NAME100 |   100 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 101 | NAME101 |   101 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 102 | NAME102 |   102 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 103 | NAME103 |   103 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 105 | NAME105 |   105 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 106 | NAME106 |   106 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 107 | NAME107 |   107 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 108 | NAME108 |   108 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
+-----+---------+-------+---------------------+---------------------+
11 rows in set (0.02 sec)

mysql>
```



# 付録 : ヒント句でオフロードコントロール

次の Document に書いている通り、SQL クエリー単位で Heat Wave へのオフロードをコントロールできます。 
https://dev.mysql.com/doc/heatwave/en/heatwave-best-practices.html

ヒント句の指定はこんな感じです。

- ON : HeatWave を使う。HeatWave が障害などで使えない場合は MDS 本体で処理を行う (ヒント句指定しない時と同じ動作)
- OFF : HeatWave を使わない。
- FORCED : 強制的に HeatWave を使う。HeatWave が障害などで使えない場合は SQL クエリーがエラーとなる

```
SELECT /*+ SET_VAR(use_secondary_engine = ON) */ * FROM account WHERE subid BETWEEN 100 and 110;
SELECT /*+ SET_VAR(use_secondary_engine = OFF) */ * FROM account WHERE subid BETWEEN 100 and 110;
SELECT /*+ SET_VAR(use_secondary_engine = FORCED) */ * FROM account WHERE subid BETWEEN 100 and 110;
```



ON : HeatWave を使うけど、使えない場合はMDS本体で処理を行う (ヒント句指定しない時と同じ動作)

```
EXPLAIN SELECT /*+ SET_VAR(use_secondary_engine = ON) */ * FROM account WHERE subid BETWEEN 100 and 110;
```



実行計画

```
mysql> EXPLAIN SELECT /*+ SET_VAR(use_secondary_engine = ON) */ * FROM account WHERE subid BETWEEN 100 and 110;
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------------------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows     | filtered | Extra                                     |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------------------------------------+
|  1 | SIMPLE      | account | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 97926422 |    11.11 | Using where; Using secondary engine RAPID |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql>
```



OFF : HeatWave に同期しててもオフロードしない

```
EXPLAIN SELECT /*+ SET_VAR(use_secondary_engine = OFF) */ * FROM account WHERE subid BETWEEN 100 and 110;
```



実行計画

```
mysql> EXPLAIN SELECT /*+ SET_VAR(use_secondary_engine = OFF) */ * FROM account WHERE subid BETWEEN 100 and 110;
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows     | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------+
|  1 | SIMPLE      | account | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 97926422 |    11.11 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql>
```



FORCED

```
EXPLAIN SELECT /*+ SET_VAR(use_secondary_engine = FORCED) */ * FROM account WHERE subid BETWEEN 100 and 110;
```



実行計画

```
mysql> EXPLAIN SELECT /*+ SET_VAR(use_secondary_engine = FORCED) */ * FROM account WHERE subid BETWEEN 100 and 110;
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------------------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows     | filtered | Extra                                     |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------------------------------------+
|  1 | SIMPLE      | account | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 97926422 |    11.11 | Using where; Using secondary engine RAPID |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-------------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql>
```



HeatWave が無効時は、すぐにエラーが返ってくる

```
mysql> SELECT /*+ SET_VAR(use_secondary_engine = FORCED) */ * FROM account WHERE subid BETWEEN 100 and 110;
ERROR 3889 (HY000): Secondary engine operation failed. use_secondary_engine is FORCED but query could not be executed in secondary engine.
mysql>
```







# 付録 : HeatWave 連携解除

同期状態

```
mysql> SELECT NAME, LOAD_STATUS FROM performance_schema.rpd_tables, performance_schema.rpd_table_id WHERE rpd_tables.ID = rpd_table_id.ID;
+----------------+---------------------+
| NAME           | LOAD_STATUS         |
+----------------+---------------------+
| sugi01.account | AVAIL_RPDGSTABSTATE |
+----------------+---------------------+
1 row in set (0.00 sec)

mysql>
```



Alter Table で、HeatWave の連携解除可能

```
ALTER TABLE account SECONDARY_UNLOAD;
```



EMPTY

```
mysql> SELECT NAME, LOAD_STATUS FROM performance_schema.rpd_tables, performance_schema.rpd_table_id WHERE rpd_tables.ID = rpd_table_id.ID;
Empty set (0.00 sec)

mysql>
```



# 付録 : HeatWave 停止の動作

OCI Console で停止可能

![1608973635756.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/d04b7b04-7f7d-08b4-cad7-94a904dfa97c.png)



Stop

![1608973657575.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/dee4a043-4458-a8a2-d8b8-faa3dba3e99c.png)



全 Node が Updating となる

![1608973722852.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/9c0bd6b6-c68c-49c6-ca9e-7d6408dfc9f3.png)



Updating になると、データ同期率が 0% になる

```
mysql> SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'rapid_load_progress';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 0.000000       |
+----------------+
1 row in set (0.00 sec)

mysql>
```



一定時間後、HeatWave の Status が Inactive になる

![1608978307537.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/998a8ceb-d2bf-e3c3-ed78-d8e0a7b63ff8.png)







# 付録 : HeatWave 起動の動作

停止状態から起動すると、一定時間後 Active になる

![1608978572408.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/51d979bb-bb8c-9c62-ae96-a7312b9629d4.png)



ただ、Active になっても Table は自動的に同期されない

```
mysql> SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'rapid_load_progress';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 0.000000       |
+----------------+
1 row in set (0.00 sec)

mysql>
```



手動で同期開始コマンドを実行する必要がある

```
ALTER TABLE account SECONDARY_LOAD;
```



# 付録 : HeatWave 再起動時の動作

Restart

![1608978896240.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/a5365031-510c-2555-e6f5-21044e35bc57.png)



Restart

![1608978922092.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104247/a0962aee-3b38-2b3e-ab39-15f734d6c47c.png)



Updating になると、データ同期率が 0% になる

```
mysql> SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'rapid_load_progress';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 0.000000       |
+----------------+
1 row in set (0.00 sec)

mysql>
```



起動時と同様に、Active になっても Table は自動的に同期されない

```
mysql> SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'rapid_load_progress';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 0.000000       |
+----------------+
1 row in set (0.00 sec)

mysql>
```



手動で同期開始コマンドを実行する必要がある

```
ALTER TABLE account SECONDARY_LOAD;
```





# 付録 : リアルタイム同期の確認

現状の結果。HeatWave に同期している状態。

```
mysql> SELECT * FROM account WHERE subid BETWEEN 100 and 110;
+-----+---------+-------+---------------------+---------------------+
| id  | name    | subid | created_at          | updated_at          |
+-----+---------+-------+---------------------+---------------------+
| 100 | NAME100 |   100 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 101 | NAME101 |   101 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 102 | NAME102 |   102 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 103 | NAME103 |   103 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 105 | NAME105 |   105 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 106 | NAME106 |   106 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 107 | NAME107 |   107 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 108 | NAME108 |   108 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 104 | NAME104 |   104 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 109 | NAME109 |   109 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 110 | NAME110 |   110 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
+-----+---------+-------+---------------------+---------------------+
11 rows in set (0.03 sec)

mysql>
```



UPDATE

```
UPDATE account SET name="NAME110_Updated" WHERE id = 110;
```



直ぐに更新されている

```
mysql> SELECT * FROM account WHERE subid BETWEEN 100 and 110;
+-----+-----------------+-------+---------------------+---------------------+
| id  | name            | subid | created_at          | updated_at          |
+-----+-----------------+-------+---------------------+---------------------+
| 109 | NAME109         |   109 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 110 | NAME110_Updated |   110 | 2020-12-26 12:04:38 | 2020-12-26 12:04:38 |
| 104 | NAME104         |   104 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 100 | NAME100         |   100 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 101 | NAME101         |   101 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 102 | NAME102         |   102 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 103 | NAME103         |   103 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 105 | NAME105         |   105 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 106 | NAME106         |   106 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 107 | NAME107         |   107 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
| 108 | NAME108         |   108 | 2020-12-26 10:45:13 | 2020-12-26 10:45:13 |
+-----+-----------------+-------+---------------------+---------------------+
11 rows in set (0.05 sec)

mysql>
```





# 付録 : HeatWave 有効時に1億レコード INSERT

test01.account テーブルを同期中

```
mysql> SELECT NAME, LOAD_STATUS FROM performance_schema.rpd_tables, performance_schema.rpd_table_id WHERE rpd_tables.ID = rpd_table_id.ID;
+----------------+---------------------+
| NAME           | LOAD_STATUS         |
+----------------+---------------------+
| sugi01.account | AVAIL_RPDGSTABSTATE |
| test01.account | AVAIL_RPDGSTABSTATE |
+----------------+---------------------+
2 rows in set (0.00 sec)

mysql>
```



1億データの Insert : 10分46秒 (HeatWave 同期していないときとさほど変わらない)

```
mysql> INSERT INTO account(name, subid)
    -> SELECT
    ->   CONCAT('NAME' , @rownum := @rownum + 1),@rownum
    -> FROM
    ->   sample AS s1,
    ->   sample AS s2,
    ->   sample AS s3,
    ->   sample AS s4,
    ->   sample AS s5,
    ->   sample AS s6,
    ->   sample AS s7,
    ->   sample AS s8,
    ->   (SELECT @rownum := 0) AS v;
Query OK, 100000000 rows affected, 2 warnings (10 min 46.39 sec)
Records: 100000000  Duplicates: 0  Warnings: 2

mysql>
```



# 付録 : 同期テーブルを追加したときの挙動

1テーブルしか同期していない状態

```
mysql> SELECT NAME, LOAD_STATUS FROM performance_schema.rpd_tables, performance_schema.rpd_table_id WHERE rpd_tables.ID = rpd_table_id.ID;
+----------------+-----------------------+
| NAME           | LOAD_STATUS           |
+----------------+-----------------------+
| sugi01.account | AVAIL_RPDGSTABSTATE   |
+----------------+-----------------------+
1 rows in set (0.00 sec)

mysql>
```



同期率 100%

```
mysql> SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'rapid_load_progress';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 100.000000     |
+----------------+
1 row in set (0.00 sec)

mysql>
```



test01.account テーブルの同期を開始

```
ALTER TABLE account SECONDARY_LOAD;
```



同期率が50% になる
1個目の Table が同期完了していて、2個目の Table を同期している途中のため

```
mysql> SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'rapid_load_progress';
+----------------+
| VARIABLE_VALUE |
+----------------+
| 51.827686      |
+----------------+
1 row in set (0.00 sec)

mysql>
```



ステータス

```
mysql> SELECT NAME, LOAD_STATUS FROM performance_schema.rpd_tables, performance_schema.rpd_table_id WHERE rpd_tables.ID = rpd_table_id.ID;
+----------------+-----------------------+
| NAME           | LOAD_STATUS           |
+----------------+-----------------------+
| sugi01.account | AVAIL_RPDGSTABSTATE   |
| test01.account | LOADING_RPDGSTABSTATE |
+----------------+-----------------------+
2 rows in set (0.00 sec)

mysql>
```



2個目のテーブルを同期している間に、1個目のテーブルにクエリーを投げても高速に返す (HeatWave にオフロードできている)

```
mysql> SELECT * FROM account WHERE subid BETWEEN 100 and 110;
+-----+---------+-------+---------------------+---------------------+
| id  | name    | subid | created_at          | updated_at          |
+-----+---------+-------+---------------------+---------------------+
| 104 | NAME104 |   104 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 109 | NAME109 |   109 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 110 | NAME110 |   110 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 100 | NAME100 |   100 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 101 | NAME101 |   101 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 102 | NAME102 |   102 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 103 | NAME103 |   103 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 105 | NAME105 |   105 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 106 | NAME106 |   106 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 107 | NAME107 |   107 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
| 108 | NAME108 |   108 | 2020-12-26 01:59:10 | 2020-12-26 01:59:10 |
+-----+---------+-------+---------------------+---------------------+
11 rows in set (0.03 sec)

mysql>
```





# 参考URL

Performance
https://www.oracle.com/jp/mysql/heatwave/performance/

GitHub
https://github.com/oracle/heatwave-tpch

Document
https://docs.oracle.com/en-us/iaas/mysql-database/doc/heatwave1.html

HeatWave User Guide
https://dev.mysql.com/doc/heatwave/en/

SQLで大量のテストデータ作成
https://qiita.com/cobot00/items/8d59e0734314a88d74c7