【GCP】Schedule QueryとCloudSQL Federationを組み合わせて超簡単にMySQLデータをBigQueryへコピーする

# はじめに
ここ最近、実務でBigQuery周りを整備する機会があったため、Google Cloud Nextで発表されてからずっと気になっていたBigQuery周りの新機能・[CloudSQL Federation](https://cloud.google.com/bigquery/docs/cloud-sql-federated-queries)を使ってみました。

使ってみると、**Embulk・DigdagのようなETLツールを扱えない非エンジニアでも、大変簡便にBigQueryにCloudSQLのデータを蓄積できるような代物であり**、少し感動したのでそちらについて紹介していきます。

# 対象読者
- データ分析基盤を構築中、または、保守運用中のエンジニアの方々
- 購買データ等をBigQueryにデータを集約して分析したいけど、エンジニアリソースがなくてお困りのマーケター・セールスの方々

# CloudSQL Federationの概要
今年発表されたBigQuery周りの新機能であり、これを使うことで、BigQueryからCloudSQL（MySQL・PostgreSQL）のデータにアクセスできるようになります。（2019.11.22現在、β版です。）

用途としては、エンジニア向けというよりは非エンジニアがMySQLのデータなどをサクッと分析したい時に活用しやすいものかなと考えられ、使用するメリットとしては、下記3点が挙げられます。

1. CloudSQLに保存されているデータをリアルタイムに分析することが可能
2. セキュアな接続が可能なため、購買データなどを扱う上で安全
3. **取得したCloudSQLのデータはBigQuery側にコピー可能**、且つ、**Schedule Queryと組み合わせれば、定期的にCloudSQLデータをBigQueryにエクスポート可能**なため、Embulk等を使わずとも、非エンジニアでも簡便にBigQueryにデータを蓄積することができるようになる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/4cfb27d8-5cac-6d9c-6884-014882ae84a6.png)
（参考：[Google Cloud Next '19 ブレイクアウトセッション: データ ウェアハウスのあるべき姿と BigQuery の新機能](https://youtu.be/mgJYCskamXs?t=1167)）

# CloudSQL Federationの使い方
GCPのアカウントの用意や、クレジットカードの登録などは既に済ませている前提ですのでご了承下さい。
また、今回は、例として、下図のようにBigQuery中にデータセット（ds_test）の中に、user_testというテーブルを用意した状態から始めます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/44c2ee54-22ad-ecea-07b3-a435b75bdc01.png)

## 1. BigQueryとCloudSQLの接続方法
まず、左側の「リソース」タブのところにある「＋データを追加」という部分をクリックします。
すると、「接続を作成」というタブが出てくるので、そこをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/29661cea-4142-2b7f-feb1-6aab42bf7cab.png)

初めての操作の時は、「BigQuery Connection APIを有効化する」というポップアップが出てくるので、「APIを有効化する」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/5ea48fad-fd45-86a3-c0ba-c0011ce20285.png)

先程の「接続を作成」を押すと、以下のようにパラメータを入力する画面が出てくるので、良しなに入力して下さい。
なお、Cloud SQL インスタンスIDについては、Cloud SQLの「インスタンス接続名」を入力すればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/c1800d4d-ee06-0f59-885f-9ee9f90972c7.png)

接続が完了すると、リソース一覧に「外部接続」が作成されていることが分かり、中身を見てみると、接続情報を確認できます。
なんと、たったこれだけで、BigQueryからCloudSQLへの接続は完了です！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/ad399b08-500a-2f06-e5d3-3ac652b32b04.png)

接続が完了したので、次に、BigQueryからCloudSQLのデータを取得するためのクエリを書いていきます。

## 2. クエリの書き方
基本文法は以下の通りです。

connection_id の部分は、project_id.location_id.connection_id という形で記述し、external_database_query の部分にSQLを記述する形になります。

```sql:基本文法
SELECT * FROM EXTERNAL_QUERY(connection_id, external_database_query);
```

より具体的に書くと以下のような形になります。

```sql:具体例1
SELECT * FROM EXTERNAL_QUERY(
"mycurryapp.asia-northeast1.cloudsql-mycurryapp", 
"SELECT * FROM users WHERE created_at BETWEEN '2019-11-22 00:00:00' AND '2019-11-22 23:59:59';"
);
```

その他の例として、MySQLやPostgreSQLに組み込まれている関数は普通に使用できるので、個人情報部分のハッシュ化や、CAST関数によるdatetime型のdate型への変換、DATE関数を用いた日時指定などもできます。

```sql:具体例2
SELECT * FROM EXTERNAL_QUERY(
'mycurryapp.asia-northeast1.cloudsql-mycurryapp', 
'''
SELECT id, 
  MD5(name) AS name, 
  MD5(email) AS email, 
  created_at, 
  CAST(created_at AS date) AS partition_date
FROM users 
WHERE created_at BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY) AND CURRENT_DATE();
'''
);
```

## 3. Schedule Queryによるバッチ処理
さて、以上のように、BigQueryとCloudSQLを繋ぎ込むことで、

1. CloudSQLに保存されているデータをリアルタイムに分析することが可能
2. read onlyでセキュアにアクセス可能なため、購買データなどを扱う上で安全

という2つのメリットを享受することができるようになりました。

更に、BigQueryの`Schedule Query`という機能を利用すると、決まった時間に決まったクエリを実行するように設定することができます。
**しかも、クエリを実行して取得したデータは、BigQuery側のテーブルに保存することができるため、従来EmbulkのようなETLツールで実装していたMySQLからBigQueryへの転送処理など実装する必要はなくなるのです！**
非エンジニアでもUI上でポチポチするだけでできちゃうので、`CloudSQL Federation × Schedule Query`の組み合わせは本当に便利だと思います。

Schedule Query自体は以前からある機能ですが、この機会に、簡単に使用方法と触っていて気付いたことを下記していきます。

まず、Schedule Queryを使うには、BigQuery画面の左側にある「スケジュールされたクエリ」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/f142698e-2836-f036-90d8-dd2ed2e19684.png)

Schedule Queryを初めて使用する場合は、「BigQuery Data Transfer API」を有効化する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/1872e047-4741-dd0d-8226-f288adcf1614.png)

BigQuery Data Transfer APIを有効化すると、このような画面が現れるので、「＋スケジュールされたクエリを作成」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/0605c043-4433-b5db-9b9e-21b7adf69c77.png)

すると、新規クエリ作成画面が開くので、CloudSQL Federationの文法に従ってバッチ処理用のSQLを記述していきます。
その後、「クエリのスケジュール」→「スケジュールされたクエリを新規作成」と進みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/517caa69-c469-8d04-26bd-bd5d9c798d17.png)

続いて、Schedule Queryの新規作成画面が現れるので、良しなに入力し、「スケジュール」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/5966f0b3-21ef-7050-f3b2-0fe48ad732c7.png)

ここで1点、触っていて気付いたこととしては、DATE関数を使って、1日前の00:00:00~23:59:59までのデータを取得するようなバッチ処理を記述する場合は、日本時間のAM9:00（＝標準時間のAM0:00）以降でスケジュールを組む必要があるようです。
CloudSQLもBigQueryも東京リージョンで使っていたのですが、実験したところ、CloudSQLのDATE関数が日本時間ではなく、標準時間の方で処理されるようでした。

```sql
-- 日本時間の2019-11-22 00:00:00 = 標準時間の2019-11-21 18:00:00にDATE関数を使用した場合
SELECT DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY);
-> 2019-11-21

-- 日本時間の2019-11-22 08:00:00 = 標準時間の2019-11-21 23:00:00にDATE関数を使用した場合
SELECT DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY);
-> 2019-11-21

-- 日本時間の2019-11-22 09:00:00 = 標準時間の2019-11-22 00:00:00にDATE関数を使用した場合
SELECT DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY);
-> 2019-11-22
```

設定完了後、確認すると、きちんとスケジュールされたクエリが出来上がっていることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307533/ba72d67e-2f2f-9b03-344d-b5b0dabb7533.png)

以上の簡単な操作によって、従来EmbulkのようなETLツールで実装していたバッチ処理をBigQuery上で完結させることができるようになりました！

# まとめ・所感
- 今年発表されたBigQueryの新機能・CloudSQL Federationの使用方法についてまとめました。
- 用途としては、エンジニア向けというよりは非エンジニアが分析したい時に活用しやすいものかなと考えられ、使用するメリットとしては、下記3点が挙げられます。
  1. CloudSQLに保存されているデータをリアルタイムに分析することが可能
  2. read onlyでセキュアにアクセス可能なため、購買データなどを扱う上で安全
  3. Schedule Queryと組み合わせることで、Embulk等を使わずとも、非エンジニアでも簡便にBigQueryにデータを蓄積することができるようになる
- 実際に使用してますが、大変便利な機能です。ただデータを貯めれば良いなどの、シンプルな要件に対しては、特に問題なく利用できるのではないかと思います。
- 一方で、UI上での操作が多いため、設定ミスに気付きにくい・やり直しが面倒臭い・複数プロジェクトに横展しにくい、などの辛みもあり、重要な部分や使い回すような部分についてはTerraformなどでコード化して管理する方がベターだと思います。
- 近いうちに、Terraformでコード管理できるか実験してみようと思っているので、上手く行ったらまた記事にしたいと思います。

# 参考URL
- [Cloud SQL 連携クエリ](https://cloud.google.com/bigquery/docs/cloud-sql-federated-queries)
- [Google Cloud Next '19 ブレイクアウトセッション: データ ウェアハウスのあるべき姿と BigQuery の新機能](https://youtu.be/mgJYCskamXs?t=1167)
- [最速でBigQuery の Cloud SQL federated queryを試してみる（Cloud SQLをBQに簡単にバックアップできるよ）](https://medium.com/google-cloud-jp/%E6%9C%80%E9%80%9F%E3%81%A7bigquery-%E3%81%AE-cloudsql-federated-query%E3%82%92%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B-cloudsql%E3%82%92bq%E3%81%AB%E7%B0%A1%E5%8D%98%E3%81%AB%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88-f04e6dca1cd3)
- [クエリのスケジューリング](https://cloud.google.com/bigquery/docs/scheduling-queries?hl=ja)