【Google Cloud】Cloud SQL for SQL Server へのデータ移行 (gcloud CLI)

# 0. はじめに
オンプレミス SQL Server 上のデータベースを Cloud SQL for SQL Server に移行する方法として、SQL Server の バックアップファイル (.bak) を利用することができます。
[【Google Cloud】Cloud SQL for SQL Server へのデータ移行 (Google Cloud コンソール)](https://qiita.com/nobtak/items/d7bc287c475471278116) では、Google Cloud コンソールから SQL Server の バックアップファイルを利用したデータベースのインポートの方法についてまとめてみましたが、現時点 (2024年7月時点) において、Google Cloud コンソール上から **トランザクション ログのバックアップを利用したデータベースのインポート処理を実施することが出来ません。**

しかしながら、**gcloud CLI から データベースのインポートコマンドを実行することで、SQL Server 完全バックアップとトランザクション ログ (以下 TLOG) バックアップを組み合わせたデータベースのインポート処理を実施することが可能**となっています。

今回、**gcloud CLI を利用してSQL Server 完全バックアップと TLOG バックアップを組み合わせたデータベースのインポート処理を実施する方法**についてまとめてみようと思います。

# 目次
[0. はじめに](#0-はじめに)
[1. Cloud SQL へのデータ移行](#1-cloud-sql-へのデータ移行)
　- [1.1 オンプレミス SQL Server 上で完全バックアップを作成](#11-オンプレミス-sql-server-上で完全バックアップを作成)
　- [1.2 完全バックアップファイル を Cloud Storage バケットにアップロード](#12-完全バックアップファイルを-cloud-storage-バケットにアップロード)
　- [1.3 完全バックアップファイル を Cloud SQL for SQL Server へインポート](#13-完全バックアップファイル-を-cloud-sql-for-sql-server-へインポート)
　- [1.4 オンプレミス SQL Server 上で TLOG バックアップを作成](#14-オンプレミス-sql-server-上で-tlog-バックアップを作成)
　- [1.5 TLOG バックアップファイルを Cloud Storage バケットにアップロード](#15-tlog-バックアップファイルを-cloud-storage-バケットにアップロード)
　- [1.6 TLOG バックアップファイル を Cloud SQL for SQL Server へインポート](#16-tlog-バックアップファイル-を-cloud-sql-for-sql-server-へインポート)
　- [1.7 インポートしたデータベースのステータスを ONLINE に変更](#17-インポートしたデータベースのステータスを-online-に変更)
[2. 制約事項](#2-制約事項)

# 1. Cloud SQL へのデータ移行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/3b9fa8f2-f2c1-170c-6760-9642937d6271.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/9bf33c6f-3209-2e7e-55c9-3dc980622dc5.png)

## 1.1. オンプレミス SQL Server 上で完全バックアップを作成
1\) SQL Server Management Studio (以下 SSMS) , SQLCMD などのツールからオンプレミス SQL Server に接続します。
2\) データ移行対象のデータベースの完全バックアップを作成します。
```ruby:完全バックアップ コマンド (例)
use master
go
backup database GCSDB to disk = 'c:\backup\GCSDB.bak'
go
```
## 1.2. 完全バックアップファイルを Cloud Storage バケットにアップロード
1\) Google Cloud コンソールにログインします。
2\) Cloud Storage - バケット - 任意のバケットを選択します。
3\) 「**ファイルをアップロード**」を選択し、作成した **SQL Server 完全バックアップファイル (.bak)** をアップロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/d8106045-73a0-792c-4a4d-552c5f78e739.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/3554a143-3dae-12af-c033-5c6bdcfbebf3.png)


## 1.3. 完全バックアップファイル を Cloud SQL for SQL Server へインポート
1\) **gcloud CLI コマンドを実行可能な環境**にログインします。
※ Google Cloud コンソール から Cloud Shell を起動、もしくは CLI ツールがインストールされた環境にログインします。
2\) **「gcloud sql import ... --bak-type=FULL --no-recovery」** コマンドを実行し、完全バックアップファイル (.bak) からデータベースを **「NORECOVERY」** モードでインポートします。
```:完全バックアップからデータベースを「NORECOVERY」モードでインポートするコマンド (例)
gcloud sql import bak <インスタンス名> gs://<バックアップファイル (.bak) を配置したCloud Storageのパス> --database=<データベース名> --bak-type=FULL --no-recovery
```
```:
$ gcloud sql import bak gcsql01 gs://sql*******/backup/GCSDB.bak --database=GCSDB --bak-type=FULL --no-recovery
Data from [gs://sql*******/backup/GCSDB.bak] will be imported to [gcsql01].

Do you want to continue (Y/n)?  y

Importing data into Cloud SQL instance...done.                                                                                                                                                                                                    
Imported data from [gs://sql*******/backup/GCSDB.bak] into [https://*******.googleapis.com/sql/v1beta4/projects/*******004/instances/gcsql01].
```

</br>

**【補足】**
- **「NORECOVERY」モードでインポートすると、Cloud SQL for SQL Server 上のデータベースのステータスは「RESTORING」** になります。
</br>

- **データベースのステータスが「RESTORING」** の状態時にのみ、完全バックアップからインポートしたデータベースに対して、差分データベース、TLOG ログ バックアップを追加でインポートが可能となります。
</br>


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/5c0086ed-4eac-1b63-6ce4-9a3e2777f0c9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/d46013ef-6236-6cc0-b59d-4f2d4d6016e8.png)




## 1.4. オンプレミス SQL Server 上で TLOG バックアップを作成
1\) SQL Server Management Studio (以下 SSMS) , SQLCMD などのツールからオンプレミス SQL Server に接続します。
2\) データ移行対象のデータベースの TLOG バックアップを作成します。
```ruby: TLOG バックアップ コマンド (例)
use master
go
backup log GCSDB to disk = 'c:\backup\GCSDB_LOG.bak'
go
```

※ TLOG バックアップファイルの識別子に「.bak」を指定していますが、識別子に「.trn」を指定したとしても、この後の データベース インポート処理を実施することは可能。


## 1.5. TLOG バックアップファイルを Cloud Storage バケットにアップロード
1\) Google Cloud コンソールにログインします。
2\) Cloud Storage - バケット - 任意のバケットを選択します。
3\) 「**ファイルをアップロード**」を選択し、作成した **SQL Server TLOG バックアップファイル (_LOG.bak)** をアップロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/d8106045-73a0-792c-4a4d-552c5f78e739.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/8cb43f78-6a3b-66f8-16d7-d49dc464f402.png)

## 1.6. TLOG バックアップファイル を Cloud SQL for SQL Server へインポート
1\) **gcloud CLI コマンドを実行可能な環境**にログインします。
※ Google Cloud コンソール から Cloud Shell を起動、もしくは CLI ツールがインストールされた環境にログインします。

2\) **「gcloud sql import ... --bak-type=TLOG --no-recovery」** コマンドを実行し、TLOG バックアップファイル (_LOG.bak) からデータベースを **「NORECOVERY」** モードでインポートします。
```: TLOG バックアップからデータベースを「NORECOVERY」モードでインポートするコマンド (例)
gcloud sql import bak <インスタンス名> gs://<バックアップファイル (.bak) を配置したCloud Storageのパス> --database=<データベース名> --bak-type=TLOG --no-recovery
```
```:
$ gcloud sql import bak gcsql01 gs://sql*******/backup/GCSDB_LOG.bak --database=GCSDB --bak-type=TLOG --no-recovery
Data from [gs://sql*******/backup/GCSDB_LOG.bak] will be imported to [gcsql01].

Do you want to continue (Y/n)?  y

Importing data into Cloud SQL instance...done.                                                                                                                                                                                                    
Imported data from [gs://sql*******/backup/GCSDB_LOG.bak] into [https://*******.googleapis.com/sql/v1beta4/projects/*******004/instances/gcsql01].
```
</br>

**【補足】**
- データ移行完了までに、複数回 オンプレミス SQL Server TLOG バックアップを Cloud SQL for SQL Server へ適用する必要がある場合、**TLOG バックアップについても「NORECOVERY」モードでインポートする必要があります。**
</br>

## 1.7. インポートしたデータベースのステータスを ONLINE に変更
**データベースのステータスが「RESTORING」** の状態時には、データベース上のテーブルに対して SELECT/UPDATE/DELETE/INSERT などのクエリ処理を実施することができません。
そのため、クエリ処理を実施できるようにするため、適用が必要なバックアップのインポート処理がすべて完了した後、**「gcloud sql import bak ... --recovery-only」コマンド**を実行して、データベースのステータスを **「ONLINE」** に変更します。
</br>
```:データベースの状態を「ONLINE」に変更するコマンド (例)
gcloud sql import bak gcsql01 --database=GCSDB --recovery-only
```
```:
$ gcloud sql import bak gcsql01 --database=GCSDB --recovery-only
Bring database [GCSDB] online with recovery-only.

Do you want to continue (Y/n)?  y

Bring database online...done.                                                                                                                                                                                                                     
Bring database [GCSDB] online with recovery-only.
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/d9abfbca-acdc-e6b7-2657-afa19bde7d5c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/9c753709-a740-f53f-8b3c-586f09e682b2.png)


# 2. 制約事項
Cloud SQL for SQL Server インスタンスで **「ポイントインタイムリカバリを有効にする」** が有効な状態で、**バックアップからデータベースを「NORECOVERY」モードでインポート実施すると、以下のエラーで処理が失敗**します。

```
ERROR: (gcloud.sql.import.bak) HTTPError 400: This operation is not valid for this instance.
```
そのため、バックアップからデータベースを「NORECOVERY」モードでインポートを実施する必要がある場合、事前に **「ポイントインタイムリカバリを有効にする」** を無効にする必要があるようです。
</br>
</br>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/23be2a1d-ef24-63c2-b2da-9dee9f3fbfbf.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/1f44d5fd-feb2-52b6-9a0e-954fa2fe09fe.png)
</br>
</br>

**※ 本ブログに記載した内容は個人の見解であり、所属する会社、組織とは全く関係ありません。**

**※ 2024年7月時点**