はじめに
SQL Server環境で大量データの移行を行いました。
データ移行や改修を行ったあと、必ず必要になるのが データ比較(差分確認) です。
- 本当に同じデータになっているか
- 移行漏れはないか
- 想定外の更新が起きていないか
本記事では、データ比較の手法を整理します。
データ比較の全体像
比較方法は大きく2パターンあります。
- 同一DB内を比較(SQLで比較)
- 別DBを比較(ファイル経由で比較)
まずはSQLで比較から見ていきます。
同一DB内のデータ比較
同一DB内の比較であれば、SQLだけで完結します。
完全一致比較(EXCEPT)
-- AにあってBにない
SELECT * FROM tableA
EXCEPT
SELECT * FROM tableB;
-- BにあってAにない
SELECT * FROM tableB
EXCEPT
SELECT * FROM tableA;
主キー比較(NOT EXISTS)
-- AにあってBにない
SELECT * FROM tableA A WHERE NOT EXISTS (SELECT 1 FROM tableB B WHERE B.Id = A.Id)
-- BにあってAにない
SELECT * FROM tableB B WHERE NOT EXISTS (SELECT 1 FROM tableA A WHERE A.Id = B.Id)
EXCEPT と NOT EXISTS の比較
EXCEPT の特徴
- 行全体を比較して差分を抽出する
- 両SELECTの列数・型・並びが一致している必要がある
- 結果は自動的に重複排除(DISTINCT相当)される
- NULL同士は等しいものとして扱われる
EXCEPT の注意点
- 重複行の個数差は検出できない(DISTINCT化されるため)
- 大規模テーブルではパフォーマンスが劣化しやすい
- 比較対象列を限定したい場合は明示的に列指定が必要
NOT EXISTS の特徴
- 指定条件で存在有無を判定する
- 行全体ではなく、WHERE句の条件のみを比較する
- 重複行はそのまま扱われる
- 条件を柔軟に書ける
NOT EXISTS の注意点
- NULLを含む条件では意図しない結果になることがある
- インデックスが無いと極端に遅くなる
使い分け
- 完全一致検証 → EXCEPT
- 列差分検出 → EXCEPT
- 主キー存在チェック → NOT EXISTS
- 日次差分抽出 → NOT EXISTS
- 大規模データ比較 → NOT EXISTS
別DBのデータ比較
- リンクサーバーが作れない
- 参照権限が限定的
- 運用環境で直接JOIN不可
この場合は、ファイル経由比較が現実解になります。
bcpコマンドを使ったデータ比較(bcp → WinMerge)
もっともシンプルで現場採用率が高い方法です。
手順の流れ
ServerA → bcp出力 → ファイルA
ServerB → bcp出力 → ファイルB
↓
WinMergeで比較
手順①:Serverから出力
bcp "SELECT * FROM tableA ORDER BY Id" queryout tableA.csv -w -S ServerA -T -d sample_db
bcp "SELECT * FROM tableB ORDER BY Id" queryout tableB.csv -w -S ServerB -T -d sample_db
手順②:WinMergeで比較
- 左:tableA.csv
- 右:tableB.csv
これで差分を視覚的に確認できます。
実務の重要ポイント
ORDER BY は必ず付ける
並び順が違うだけで、全件差分に見えてしまいます。
文字コードは統一する
日本語を扱う場合は -w(Unicode)推奨
OPENROWSET(BULK)を使ったデータ比較(bcp → クエリ比較)
GUIツールが使えない環境では、SQLで比較する方法もあります。
手順の流れ
ServerA → bcp出力 → CSV
ServerB → bcp出力 → CSV
↓
OPENROWSET(BULK) で差分比較
手順①:Serverから出力
bcp "SELECT * FROM tableA ORDER BY Id" queryout tableA.csv -w -t "," -S ServerA -T -d sample_db
bcp "SELECT * FROM tableB ORDER BY Id" queryout tableB.csv -w -t "," -S ServerB -T -d sample_db
手順②:差分比較
SELECT * FROM OPENROWSET(
BULK 'C:\data\tableA.csv',
DATAFILETYPE = 'widechar',
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
) AS tableA
EXCEPT
SELECT * FROM OPENROWSET(
BULK 'C:\data\tableB.csv',
DATAFILETYPE = 'widechar',
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
) AS tableB
WinMerge と OPENROWSET+EXCEPT の比較
WinMerge の特徴
- GUIで直感的に差分を確認できる
- 行単位の違いが視覚的に分かりやすい
- SQLを書かずに比較できる
- 小~中規模データの確認に向いている
WinMerge の注意点
- 行順が違うと全差分扱いになる(ORDER BY必須)
- 件数が多いと表示や比較が重くなる
- バッチ化しにくい
- 列単位の厳密比較には不向き
OPENROWSET+EXCEPT の特徴
- SQLで差分行を正確に抽出できる
- バッチやスクリプトに組み込みやすい
- 大量データでも比較的スケールする
- 差分件数の把握や後続処理に向いている
OPENROWSET+EXCEPT の注意点
- 列数・型・順序が一致している必要がある
- EXCEPTは重複行の件数差を検出できない
使い分け
- 目視確認 → WinMerge
- 差分抽出・件数確認 → OPENROWSET+EXCEPT
- 本番検証や定期チェック → OPENROWSET+EXCEPT
- スポット調査 → WinMerge
まとめ
データ移行や改修後の検証では、データ比較(差分確認) が品質を担保する最後の砦になります。
重要なのは、目的と環境に応じて比較手法を使い分けることです。
同一DB内の比較
- 完全一致の検証 → EXCEPT
- 主キー存在チェックや日次差分 → NOT EXISTS
別DB間の比較
- 目視確認・スポット調査 → bcp & WinMerge
- 厳密比較・自動化 → bcp & OPENROWSET + EXCEPT
迷ったときのシンプル判断
- まず目で見たい → WinMerge
- 差分を正確に取りたい → EXCEPT / NOT EXISTS
- 定期検証・自動化 → OPENROWSET + EXCEPT
本記事の手法をベースに、現場の制約に合わせて最適な比較フローを組み立てて頂ければ幸いです。
これらの手法でデータ移行をしました。