SQL Server の Azure リフトで得たノウハウ

先日社内システムの SQL Server を SQL Managed Instance (以降 SQL MI) に移行するプロジェクトを実施しました。
その中でいくつかノウハウが取得できましたのでまとめておきたいと思います。

## システム構成
まず移行対象のシステム構成ですが、実はオンプレミスにあるスタンドアロンの SQL Serverを SQL MI に単純リフト (シフト？) すると言うだけのものです。
ですのでシステム構成図と言えるようなものでもないのですが、全体像としてはこんな感じです。

[移行前]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620633/0acf2745-1e91-43fd-a34f-550777a852f4.png)

[移行後]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620633/d8f3511f-1366-4b6c-a85d-928cdb2cd40b.png)

では次のセクションからノウハウを記載していきます。

## Synapse Analytics 専用 SQL プールの互換性
移行対象システムが BI でしたので最初は Synapse Analytics を検討したのですが、単純移行には互換性が厳しくて早々に断念しています。
一番厳しかったのは外部キーで、移行元で外部キーがバンバン張られているので影響度を見極めきることができずこれがノックアウトファクターになりました。

https://learn.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-table-constraints#table-constraints

あと事前検証では AdventureWorks 使っていましたが、そこではデータ型の制約にもバンバン引っ掛かりましたね。

https://learn.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-data-types#unsupported-data-types

Synapse Analytics が SQL Server 互換を謳っていると言えども、単純なリホスト用途はなかなか難しいなと感じました。

## Azure ポータルへのアクセスが条件付きアクセスポリシーでブロックされる
本件の構築先の Entra ID テナントは社用の Microsoft 365 も乗っている環境で、ここにはネームドロケーションでアクセス制御された条件付きアクセスポリシーが設定されています。
作業環境として Azure 仮想マシンを使用しているのですが、当然と言えば当然で Azure ポータルへのアクセスが条件付きアクセスポリシーでブロックされてしまいます。(このパターン結構多いのではないかと)
この影響を受けるのが Azure ポータルからのストレージアカウントへのアクセスで、やむなく別の環境でストレージアカウントキーを取得した上でストレージエクスプローラーからアクセスするという回り道を構築しました。
本来ならネームドロケーションに IP アドレス追加してもらえば良いんですが、そう言うのサクッといかないのが日本の情シス文化なのですよね。

## データベースメールの代替手段
SQL Server にはジョブの失敗時に通知を行う機能があり、移行前の環境ではこの通知先をメール (データベースメール) に設定していました。 で SQL MI はデータベースメールに対応してるから大丈夫だろうと思っていたら、先の Microsoft 365 環境が SMTP を許可しておらずやむなく代替手段を講ずることに。
ドメイン取得して SendGrid 立てればできることはわかっていたのですが、もろもろのリードタイムから次善策に回し本件ではアラート通知との連携にて対応しています。具体的には SQL Server 監査を SQL MI の診断設定と連携しそこから Log Analytics のクエリでアラートを構築する方式です。

https://learn.microsoft.com/ja-jp/azure/azure-sql/managed-instance/auditing-configure?view=azuresql

1. msdb データベースにデータベース監査を設定
    * 監査アクションの種類: BATCH_COMPLETED_GROUP
    <br>
2. サーバー監査を設定
    * 監査の出力先: 外部モニター
    * フィルター: [application_name] = 'SQL Agent - Job Manager' AND [statement] like '%sp_agent_log_job_history%' 
    <br>
3. SQL MI の診断設定
    * カテゴリ: SQL Security Autit Event
    * 宛先の詳細: Log Analytics ワークスペースへの送信
    <br>
4. アラートの設定
    * アラートルールのクエリ: 
      AzureDiagnostics | where Category == "SQLSecurityAuditEvents" and application_name_s == "SQLAgent - Job Manager" and statement_s contains "The step failed"

この方式は任意のテーブルに書き出した情報をアラートで引っかけることもできますので、結構汎用性が高いのではないかと思います。

## 仮想コアだけ見るとメモリが足りなくなる
本件のような単純移行がターゲットになるようなシステムでは CPU: 8コア / メモリ: 32GB あたりで構築されていることが多いんじゃないかと思います。これに対し SQL MI のメモリは Standard シリーズで 5.1GB / vCPU の割り当てとなっています。
で本件は基本的に CPU スカスカで SQL MI では CPU の性能も上がってるし 4vCPU で構築してたんですが、そうするとメモリが 20GB なのでバッチ処理でメモリが足りなくなって性能が劣化するという結果になりました。
最終的にはバッチ処理のときだけスケールアップすることで性能劣化は解消されたのですが、リソース制限はフォーカスすることなく全般押さえなさいと言うことを改めて認識した次第です。

https://learn.microsoft.com/ja-jp/azure/azure-sql/managed-instance/resource-limits?view=azuresql

## エンドポイントは 3 種類ある

https://learn.microsoft.com/ja-jp/azure/azure-sql/managed-instance/connectivity-architecture-overview?view=azuresql

SQL MI のエンドポイントは、

1. VNet ローカル エンドポイント: 同一 VNet 用
2. パブリック エンドポイント: インターネット用
3. プライベート エンドポイント: 異なる VNet 用

の 3 種類があります。
他の PaaS リソースでは同一・異なる問わずプライベートエンドポイントが VNet からのエンドポイントになることが多いですが、SQL MI の場合は <ins>同一 VNet から接続する場合プライベートエンドポイント不要かつ VNet ローカルエンドポイントの名前解決も自動的に設定されます。<ins>

ちなみに IP アドレスを使用して SQL MI に接続することはできません。

https://learn.microsoft.com/ja-jp/azure/azure-sql/managed-instance/frequently-asked-questions-faq?view=azuresql#ip-----------managed-instance---------

## おわりに
実は本件構築～テストまでは完了していますが、まだ最終移行～カットオーバー前のシステムとなっています。
ので今後 統計情報 とか 実行プラン とか 夜間停止に伴うキャッシュクリア とかに依存する問題が出てくる可能性がありますので、もしそのあたり出てきた際にはまたノウハウとして公開したいと思います。
問題が出て欲しいのか出て欲しくないのかは微妙ですが…

本稿を読んでいただきありがとうございました！