【Google Cloud】Cloud SQL for SQL Server へのデータ移行 (Google Cloud コンソール)

# 0. はじめに
オンプレミス SQL Server 上のデータベースを Cloud SQL for SQL Server に移行する方法として、SQL Server の バックアップファイル (.bak) を利用することができます。
今回、**「SQL Server バックアップファイル (.bak) を利用した Cloud SQL for SQL Server へのデータ移行方法」** についてまとめてみようと思います。

# 目次
[0. はじめに](#0-はじめに)
[1. Cloud SQL の概要](#1-cloud-sql-の概要)
[2. Cloud SQL へのデータ移行](#2-cloud-sql-へのデータ移行)
　- [2.1 オンプレミス SQL Server 上で完全バックアップを作成](#21-オンプレミス-sql-server-上で完全バックアップを作成)
　- [2.2 バックアップファイル を Cloud Storage バケットにアップロード](#22-バックアップファイルを-cloud-storage-バケットにアップロード)
　- [2.3 バックアップファイル を Cloud SQL for SQL Server へインポート](#23-バックアップファイル-を-cloud-sql-for-sql-server-へインポート)
[3. ベストプラクティス](#3-ベストプラクティス)
[4. 検証](#4-検証)
　- [4.1 Cloud SQL 移行後のデータベース所有者](#41-cloud-sql-移行後のデータベース所有者)
　- [4.2 Cloud SQL 移行後のスキーマ](#42-cloud-sql-移行後のスキーマ)
　- [4.3 Cloud SQL 移行後のテーブル列の照合順序](#43-cloud-sql-移行後のテーブル列の照合順序)
　- [4.4 追記されたバックアップファイルを利用した Cloud SQL へのインポート](#44-追記されたバックアップファイルを利用した-cloud-sql-へのインポート)
[5. 最後に](#5-最後に)

# 1. Cloud SQL の概要
Cloud SQL は、Google Cloud のフルマネージド データベース サービス (PaaS) です。
Cloud SQL では、以下の データベース エンジン (RDBMS) に対応しています。
- **SQL Server**
- **MySQL**
- **PostgreSQL**
</br>
対応された オンプレミス データベース製品と比較すると、利用できない機能が存在します。
しかしながら、以下のようなメリットがあり、利用できない機能を利用する要件がない限りは、積極的に利用することを前提に設計すると良いかと思います。

- **運用コスト削減** 
(OS レイヤの管理が不要, 標準機能による自動バックアップ, アップデート, モニタリング)
- **柔軟なスケールアップ／スケールダウン**
(オートスケールによるストレージ拡張 (**最大 64TB**),  柔軟な vCPU (**最大 48 vCPU**), メモリ (**最大 312 GB**) 設定：カスタム設定が可能)
- **簡易に高可用性構成が可能**
- **簡易にクローン作成が可能**
(アプリケーションのテスト, トラブルシューティング 目的で利用)

※詳細については「[Cloud SQL for SQL Server の特長](https://cloud.google.com/sql/docs/sqlserver/features?hl=ja) 」を参照。

# 2. Cloud SQL へのデータ移行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/d1b0478f-99c3-457c-eb78-0d09463f64e8.png)


## 2.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
```
## 2.2. バックアップファイルを Cloud Storage バケットにアップロード
1\) Google Cloud コンソールにログインします。
2\) Cloud Storage - バケット - 任意のバケットを選択します。
3\) 「**ファイルをアップロード**」を選択し、作成した **SQL Server 完全バックアップファイル (.bak)** をアップロードします。

![CloudSQLForSQLServer02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/006c980d-94db-d033-f8bb-62b072803ede.png)

![CloudSQLForSQLServer03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/7cbcb7e2-7cd5-cafe-ff43-1d4c0d598c47.png)

## 2.3. バックアップファイル を Cloud SQL for SQL Server へインポート 
1\) Google Cloud コンソールにログインします。
2\) SQL - 該当のインスタンス - 概要 を選択します。
3\) 「**インポート**」を選択し、必要項目を入力後、「インポート」を選択します。
- **パケット名／ファイル名** : 
2.2 で Cloud Storage にアップロードした バックアップファイル(.bak) を選択
- **ファイル形式** :
BAK
- **新しいデータベースの名前** :
任意のデータベース名

![CloudSQLForSQLServer04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/01cfba2e-51c2-8288-f39f-2c0628a7ec8c.png)

![CloudSQLForSQLServer05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/c42113c9-8c36-12bd-cc35-a508a7576e50.png)

4\) SQL - 該当のインスタンス - データベース より、インポートしたデータベースが正常に作成されていることを確認します。

![CloudSQLForSQLServer06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/6f87b0e5-58f6-25e0-9d52-09ceae53e697.png)


# 3. ベストプラクティス
- 移行対象のデータベースが大きい (数TB など) 場合、1つのデータベースバックアップを分割してインポートする **ストライプ インポート／エクスポート** を利用
</br>

- バックアップファイルを圧縮して Google Cloud Storage にアップロード
※ **バックアップファイル (.bak) を gzip(.gz) で圧縮**、もしくは **SQL Server の機能でバックアップファイルを圧縮**。
```ruby:完全バックアップ + 圧縮 コマンド (例)
use master
go
backup database GCSDB to disk = 'c:\backup\GCSDB.bak' with compression
go
```


※詳細については「[データのインポートとエクスポートに関するベスト プラクティス](https://cloud.google.com/sql/docs/sqlserver/import-export?hl=ja) 」を参照。

# 4. 検証
オンプレミス SQL Server 上のデータベースのバックアップ を利用して **Cloud SQL for SQL Server** へデータ移行するにあたり、検証した内容をまとめてみます。
</br>
## 4.1. Cloud SQL 移行後のデータベース所有者
**【前提条件】**
データベース所有者が ドメインユーザー もしくは sa の場合
```ruby:データベース所有者確認コマンド
use master
go
exec sp_helpdb N'GCSDB'
go
```
- **オンプレミス SQL Server**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/219a0884-f6e5-8179-6a4e-a9a868e0c389.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/edfb7b42-40a0-a1b8-970f-d35f245e095f.png)


- **Cloud SQL for SQL Server**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/9aeaeab8-b601-9c99-251d-1d59dc4397bd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/168183c4-6654-b571-141a-66b0735e5473.png)

データベース所有者が **SQL Server ログイン「sqlserver」** に変更されたことを確認。

## 4.2. Cloud SQL 移行後のスキーマ
**【前提条件】**
dbo 以外のスキーマを保持している場合
```:スキーマ確認コマンド (例)
use GCSDB
go
select sc.name as schema_name, so.name from sys.objects so
left outer join sys.schemas sc on so.schema_id = sc.schema_id
where type = 'U'
go
```
- **オンプレミス SQL Server**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/dbe1cd46-3092-581c-53c0-4c64edf504f1.png)


- **Cloud SQL for SQL Server**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/572f3a2d-0b6e-dafe-c817-5164e237021e.png)

スキーマが正しく **Cloud SQL for SQL Server** へ移行されたことを確認。

## 4.3. Cloud SQL 移行後のテーブル列の照合順序
**【前提条件】**
明示的にデータベースの既定の照合順序以外の照合順序をテーブル列に設定
```:テーブル列の照合順序確認コマンド (例)
use GCSDB
go
select object_name(object_id) as table_name, sc.name as column_name, st.name as data_type_name ,sc.collation_name
from sys.columns sc
left outer join sys.types st on sc.user_type_id = st.user_type_id
where object_id = object_id('tab1') or object_id = object_id('tab2')
go
```

- **オンプレミス SQL Server**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/61ea6ec5-649f-18fd-6524-d0a5cfc51a3f.png)

- **Cloud SQL for SQL Server**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/e527b220-6e42-416f-cf68-8362e57aebce.png)

テーブル列の照合順序が正しく **Cloud SQL for SQL Server** へ移行されたことを確認。

## 4.4. 追記されたバックアップファイルを利用した Cloud SQL へのインポート
**【前提条件】**
一つのバックアップファイルに複数回 完全バックアップを追記
```:一つのバックアップファイル (GCSDB.bak) に複数の完全バックアップを追記するコマンド (例)
use master
go
backup database GCSDB to disk = 'c:\backup\GCSDB.bak' with noinit -- 1回目
go
backup database GCSDB to disk = 'c:\backup\GCSDB.bak' with noinit -- 2回目
go
```
**【Cloud SQL for SQL Server へのインポート処理】**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/90d0ce7f-6703-b525-cf05-d76b7bb7a07b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/78233d6e-1359-95f1-f24f-8345c9ea01d0.png)

**Cloud SQL for SQL Server** へインポート処理が失敗することを確認。
Cloud SQL for SQL Server インポート処理で指定するバックアップファイル (.bak) に含めることができるデータベース バックアップは 1つのみという制限があるもよう。


## 4.5. 下位バージョンの SQL Server で作成したバックアップファイルを利用した Cloud SQL へのインポート
**【前提条件】**
**下位バージョン (SQL Server 2019)** で作成したバックアップファイルを **上位バージョン (SQL Server 2022) としてデプロイした Cloud SQL for SQL Server** へインポート


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/78fc4408-a5f4-a77b-8e46-86ecde6b6a86.png)

正常に **下位バージョン (SQL Server 2019)** で作成したバックアップファイルを **上位バージョン (SQL Server 2022) としてデプロイした Cloud SQL for SQL Server** へインポートできることを確認。
</br>

**【注意】**
上位バージョンの SQL Server バックアップを下位バージョンの SQL Server にリストアすることは、オンプレミス SQL Server でも出来ないため、同様に Cloud SQL for SQL Server でも出来ない。


# 5. 最後に
今回、**「SQL Server バックアップファイル (.bak) を利用した Cloud SQL for SQL Server へのデータ移行方法」** についてまとめてみました。
SQL Server バックアップファイル (.bak) を利用してデータ移行ができるのは、スキーマ や テーブル列に指定した照合順序などがそのまま移行されるのでとても便利ですね。
Cloud SQL for SQL Server は PaaS (Platform as a Service) のため、利用者側に 管理者権限 (sysadmin 権限) が付与されていない構成のため、管理者権限 (sysadmin 権限) が必要となる機能、コマンドの利用が制限されていますが、代わりに「**gcloud sql import bak**」などのコマンドや、システム データベース MSDB 上に **Cloud SQL for SQL Server 用のストアドプロシージャ**が別途用意されていました。
オンプレミス SQL Server を利用していた人も、Cloud SQL for SQL Server の制約、上記の差分を把握すれば、その他の 通常よく使用する機能、コマンドは オンプレミス SQL Server と変わらず、更に スケールアップ／ダウンを柔軟に実施でき、可用性を観点に実現でき、かつ、運用コストを削減できるというより多くのメリットを享受できるので、積極的に活用を検討すると良いと思いました。
</br>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3540203/0a461f11-0c50-1135-addb-acd371b04261.png)
</br>

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

※ **2024年6月時点**