はじめに
私はデータ基盤の運用保守に携わっており、主にバッチ処理まわりの保守や追加開発を担っています。
DB移行は製品ごとに覚え直すものではなく、共通の6フェーズの型で進められます。本記事はSQL Server→Snowflakeの実例で、各フェーズの目的・やること・つまずきを実務目線でまとめた保存版です。対象はSQLの基礎がある初〜中級データエンジニア、前提はWindows・Snowflakeです。
Snowflakeの公式移行ガイドでは、移行を 9つのステップ に分解しています(SQL Server to Snowflake Migration Guide)。本記事の6フェーズは、製品をまたいで使い回せるよう、この公式フレームワークを要点に絞って束ねたものです。公式手順と対応づけながら読むと理解が深まります。
環境・前提
- 移行元: SQL Server
- 移行先: Snowflake
- データの渡し方: ソースから抽出した tsvファイル をクラウドストレージ(ステージ)経由でロード
- ロード処理: 既存のSQL Server用のバッチ処理(SqlClient、Table-Valued Parametersを使用したバルクINSERT処理)をSnowflake用のバッチ処理(SqlClient同様のコーディングが可能なSnowflake .NETドライバ を使用)に修正
- 想定読者の前提知識: SQLの基礎、データウェアハウス(DWH=分析用に大量データをためる基盤)の概念をなんとなく知っている程度
実行環境は Windows を基準にしています。macOSやLinuxでのコマンドは深追いしません。必要に応じて公式ドキュメントをご確認ください。
なお、具体的な数値やテーブル名などは社外秘に配慮してマスキングしています。型と考え方が伝わることを優先しているので、その点はご容赦ください。
移行プロセスの「型」:6フェーズ
全体像は次のとおりです。以降、各フェーズを「目的 → やること → つまずきポイント」の順で見ていきます。
| フェーズ | 目的(ひとことで) |
|---|---|
| ① 事前調査・アセスメント | 何を・どれだけ・どんな依存関係で移すかを洗い出す |
| ② スキーマ変換 | 定義・データ型を移行先で“等価”に置き換える |
| ③ データ移行方式の選定 | どう運ぶか(COPY/INSERT・一括/差分)を決める |
| ④ 検証 | データ整合性と性能を確かめる |
| ⑤ 切替(カットオーバー) | リスク最小で本番を切り替える |
| ⑥ 運用・安定化 | 定常運用へ引き渡し、安定して回す |
① 事前調査・アセスメント
目的: 何を・どれだけ・どんな依存関係で移すのかを洗い出し、移行の難所を最初に見える化する。
ここを雑にやると、後のフェーズで「想定外」が次々に噴き出します。Snowflakeの公式ガイドも、計画・設計フェーズを「移行プロジェクト成功にとって最も重要」と位置づけています(同ガイド Phase 1)。
具体的に棚卸しするのは、ざっくり次の5つです。
- データベースオブジェクト: テーブル・ビューの一覧と、各テーブルの 行数とデータサイズ。これが後の移行方式と所要時間を左右します。
- 手続き型コード: ストアドプロシージャ、ユーザー定義関数、トリガー、カーソルを使った処理。移行先で「そのまま動かない」候補です。
- 自動化・ETL: ジョブのスケジュールと依存関係。
- 下流の利用者: そのDBを参照しているレポートやBIツール。
- 権限・ロール: 誰が何にアクセスしているか。
ポイント:「全部そのまま移す(リフト&シフト)」を最初の目標にしない。 公式ガイドも、使われていないオブジェクトや一時データは移行対象から外し、長年たまった“技術的負債”まで運ばないよう促しています。SQL Server特有の master / msdb / tempdb / model といったシステムDBは、Snowflakeに対応物がないので移行対象から除外します。
なお私のケースでは、SQL Serverで使っていた ユーザー定義テーブル型 がSnowflakeに無く、バッチ(バルクINSERT処理)の改修が必須でした。
この「対象を絞る判断」は、製品が変わっても通用する型です。次のDBでも、まず棚卸し → 移すものと捨てるものを仕分け、という順番は変わりません。
② スキーマ変換
目的: テーブル定義やデータ型を、移行先で“正しく等価”になるよう置き換える。
まず一般論として、移行で一番ハマりやすいのが データ型のマッピング です(私自身のケースでは後述のとおり型変換作業は発生しませんでしたが、型として知っておく価値があります)。多くは素直に対応します(例:INT → NUMBER)。一方で、注意が要るのが日時型です。公式ガイドでは次のように明記されています(同ガイド Phase 3)。
- SQL Serverの
DATETIME/DATETIME2(タイムゾーン情報を持たない)→ SnowflakeのTIMESTAMP_NTZ - SQL Serverの
DATETIMEOFFSET(タイムゾーンのオフセットを持つ)→TIMESTAMP_TZ
ここを取り違えると、タイムゾーンの情報が欠落したり、逆に余計な変換が入って値がずれたりします。
そしてもう一つ、私が「考え方を変えないといけない」と感じた最大のポイントが 制約の扱い です。
SQL Serverでは主キー・外部キーといった制約を DBエンジンが強制(enforce) してくれますが、Snowflakeではこれらの制約は 定義はできても強制されません(メタデータとして存在するだけ)。つまり データの整合性を守る責任が、DBからデータパイプライン(ETL/ELT)側へ移る のです。
この「整合性は自分のパイプラインで担保する」という発想の転換は、移行先がSnowflakeでなくクラウドDWH一般でもよく出てくる論点で、まさに型として効きます。
そのほか、T-SQL特有の書き方も置き換えが必要です(例:GETDATE() → CURRENT_TIMESTAMP()、ISNULL() → COALESCE())。カーソルによる1行ずつの処理はSnowflakeでは性能上の“やってはいけない型”なので、できる限り 集合演算(セットベース)のSQL に書き直します。Snowflakeはトリガーをサポートしないため、その役割は Stream(変更検知)+ Task(定期実行) という別パターンで作り直します。
私が経験した業務では、設計し直した部分はありません。インプットであるtsvファイルが作成されるまでの過程で、ETLは完了していたためです。Snowflakeに移行するのは、一部BI用のDBでした。ビューでは、T-SQL特有の関数を利用していますが、関数を変更したのみで、設計変更はありません。
③ データ移行方式の選定
目的: どうやってデータを運ぶかを決める。ここが設計判断の見せ場です。
まず大きく 初回の一括移行(ヒストリカル) と、その後の 差分移行(インクリメンタル) に分かれます。Snowflakeへのロードは「ソース → ステージ → ターゲット」の3段構えが基本で、データを直接ではなく、いったんクラウドストレージ(ステージ)に置いてから取り込みます(同ガイド Phase 4)。
ロード方式として、Snowflakeが高速・大量ロードの本命として推奨するのが COPY INTO <table> コマンドです。これは並列処理で動くよう設計されていて、公式は 1ファイル100〜250MB程度に分割して並列度を活かすことを勧めています。さらに重要なのが、COPY はロード履歴をターゲットテーブルのメタデータに最大64日間記録し、同じファイルの二重ロードを防ぐ点です(Loading data considerations)。冪等(同じ操作を何度実行しても結果が壊れない)に寄せやすいわけです。
本来は COPY が推奨です。ただし実際には、Snowflakeのドライバ(.NET含む)には 配列バインド(公式で言う「bulk insert」)という仕組みがあり、INSERT であっても大量データの場合は内部的に「一時ステージへ圧縮ファイルをアップロード → それを参照してロード」という、COPY に近い動きをします。公式は INSERT INTO ... VALUES で複数行を1バッチ投入できると説明し、その一方で「配列バインドよりも COPY などのロード方式を推奨する」とも明記しています(Bind variables。大量配列の自動ステージングは CLIENT_STAGE_ARRAY_BINDING_THRESHOLD で制御)。
つまり「INSERT か COPY か」は見た目ほどきれいに割り切れません。ドライバが裏で何をしているかを知っているかが、既存スクリプト(INSERT)をそのまま活かすか書き換えるかの判断を分けます。この“裏側の挙動”は単体で深掘りする価値があるので、別記事として切り出す予定です。
④ 検証(データ整合性+性能テスト)
目的: 移行後のデータが正しいこと、そして実用に耐える速度で動くことを確かめる。
検証は 行数を数えるだけでは不十分です。公式ガイドは多層の検証を勧めています(同ガイド Phase 7)。
- ファイル/オブジェクト検証: チェックサムやハッシュで、転送中にファイルが壊れていないか確認。
-
集計レベルの照合: 移行元と移行先の双方で、行数や
SUM/AVG/MIN/MAXを突き合わせる。 - セルレベルの照合(データ差分): 業務上重要なテーブルは、サンプルを抽出して1セルずつ比較し、型変換や変換ロジックの取りこぼしを捕まえる。
そしてこのフェーズには 性能テスト も含まれます。私の案件では、ここで「DMLの処理単位件数(1回のDMLで何件処理するか)を変えると処理時間が大きく変わる」という現象に行き当たりました。少なすぎる件数だとオーバーヘッドがかさみ、件数を増やすと内部処理が効いて大幅に短縮できた、という話です。一方で ウェアハウス(計算リソース)のサイズは、この件数レンジでは処理時間にほとんど影響しませんでした。
これは公式の説明とも整合します。ウェアハウスの拡大は 大きく複雑なクエリには効く一方、小さく単純な処理では効果が出にくいとされています(Increasing warehouse size / Warehouse considerations)。「サイズを上げれば速くなる」は万能ではない、という型の知見です。
計測の具体(件数×ウェアハウスサイズ×処理時間の表、ウォームアップ・結果キャッシュの扱い、Query Profileの読み方)は、別記事②「Snowflakeの性能テスト 最適手順」で深掘り予定です。本記事では「検証フェーズの中に性能テストが位置する」という型の位置づけにとどめます(別記事②は未公開のため、公開後にここへURLを差し込みます)。
⑤ 切替(カットオーバー)
目的: 本番を移行先に切り替える。リスクを最小化する切り方を選ぶ。
ここで大事なのは、いきなり全部を切り替える「ビッグバン」を避けることです。公式ガイドも、影響範囲(blast radius)を抑える段階的な切替を推奨しています(同ガイド Phase 8)。
- 段階的ロールアウト(推奨): アプリ・レポート・業務単位で1つずつ移していく。
- 並行稼働(パラレルラン): しばらく旧システムと新システムを並行で動かし、両方の出力を突き合わせて一致を確認してから旧系を止める。
- ブリッジ戦略: 移行の途中でも、利用者が新旧2つのシステムを使い分けずに済むよう、見かけ上ひとつのビューに見せる。
加えて、ロールバック計画(問題が出たら戻せる準備)と、最終切替前のチェックリスト(権限・ロール・サービスアカウント・監視の有効化)、関係者の正式な合意(サインオフ)も型の一部です。リリース手順書を書くときの考え方を、そのまま一般化できます。
業務では、並行稼働を計画しています。懸念事項としては、実行環境に負荷がかかり、処理時間が延びる可能性があります。
⑥ 運用・安定化
目的: 移行はゴールではなくスタート。定常運用に引き渡し、安定して回す。
切替が終わると、プラットフォームの“運用フェーズ”が始まります。Snowflakeの文脈では、性能チューニングとコスト最適化は表裏一体です(同ガイド Phase 9)。型として押さえるのは次あたりです。
- 計算リソースの適正化: ウェアハウスを用途ごとに分け、アイドル時に自動停止(auto-suspend)させる。
- 遅いクエリの可視化: Snowflakeの Query Profile で実行内容を分析する。
- 再実行(リトライ)設計: 一時的な失敗を安全に再実行できるようにする。私の案件では「特定エラーだけ条件付きでリトライする」実装をここに置きました(詳細は拙記事『なぜ“特定エラーだけ”リトライにしたか』『snowコマンドを“特定エラーだけ”リトライするPowerShell実装』を参照。公開URLは後日差し込み)。
- 監視と引き継ぎ: 監視・アラートを整え、定常運用チームに渡せる状態にする。
監視・再実行・コスト管理という運用の型は、相手の製品が何であっても効くスキルです。
まとめ・学び
- データベース移行は、製品ごとにゼロから覚え直すものではなく、①事前調査 → ②スキーマ変換 → ③移行方式の選定 → ④検証 → ⑤切替 → ⑥運用 という 製品非依存の「型」 で捉えられます。
- 各フェーズで効く判断軸(移す対象を絞る/整合性をパイプラインで守る/推奨と既存事情のトレードオフ/サイズより処理設計/段階的切替)は、Oracleでも PostgreSQLでも横展開できます。
- だからこそ、一度きちんと移行をやり切った経験は 持ち出し可能なポータブルスキルになります。私自身、SQL Server→Snowflakeで得た型を、次の現場の判断に使用できるようにしたいと考えています。
次は、この型の④検証で触れた 性能テスト を、計測設計のレベルまで深掘りした記事を予定しています(公開後にここへリンクを追加します)。
参考リンク(公式ドキュメント)
- SQL Server to Snowflake Migration Guide — 移行の全体フレームワーク・型マッピング・各フェーズ
- Loading data — considerations — COPYのロード方式・ロード履歴による二重ロード防止
- Bind variables — 配列バインド(bulk insert)とCOPY推奨
- Increasing warehouse size — ウェアハウスサイズと性能の関係
- Warehouse considerations — ウェアハウス運用の考慮点