3TB規模のデータベースを移行するときの計画の立て方
公開日 2026-08-13 · 更新日 2026-08-13 · 最終検証日 2026-08-13
結論
3TB規模の移行計画は、(1) オブジェクト単位で実サイズを測る、(2) 全停止/初期ロード+CDC追いつき/二重書き込みのどれにするかを許容停止時間から決める、(3) 代表データで試験実行して所要時間を実測する、(4) 整合性検証の方法を決める、(5) 切り戻し条件と復帰不能点を定義する、の順で組み立てます。所要時間の目安値を先に置いてはいけません。計画に載せてよい数字は、自環境での試験実行から得た実測値だけです。
この文書の適用条件
| 対象製品 | データベース移行(MySQL系 / SQL Server 系ほか) |
|---|---|
| 確認バージョン | サイズ計測SQLはMySQL 5.7 / 8.0 系と SQL Server 2012 以降で確認。移行ツールのバージョンは各環境で要確認 |
| 適用環境 | オンプレミス、AWS、Azure(および相互間の移行) |
| 必要権限 | サイズ計測はメタデータ参照権限(SQL Serverは `VIEW DATABASE STATE`)。ダンプ取得は対象スキーマの `SELECT` |
| 実行影響 | 計測SQLは影響なし。ダンプ取得と試験ロードは移行元・移行先の双方に負荷をかける |
| 再起動 | 計測は不要。切り替え時の停止有無は選ぶ方式による |
| 最終検証日 | 2026-08-13 |
そのまま実行できるコマンド
- 対象
- MySQL 5.7 / 8.0、Aurora MySQL 2.x / 3.x
- 権限
- `information_schema` の参照権限
- 変更作業
- なし(参照のみ)
- Production実行
- 可能
-- 対象: MySQL 5.7 / 8.0、Aurora MySQL 2.x / 3.x
-- 権限: information_schema の参照権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
TABLE_SCHEMA,
TABLE_NAME,
ENGINE,
TABLE_ROWS AS estimated_rows,
ROUND(DATA_LENGTH / 1024 / 1024 / 1024, 2) AS data_gb,
ROUND(INDEX_LENGTH / 1024 / 1024 / 1024, 2) AS index_gb,
ROUND(DATA_FREE / 1024 / 1024 / 1024, 2) AS free_gb,
ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024 / 1024, 2) AS total_gb
FROM information_schema.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC;
-- スキーマ単位の合計(全体像の把握用)
SELECT
TABLE_SCHEMA,
COUNT(*) AS table_count,
ROUND(SUM(DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024 / 1024, 2) AS total_gb
FROM information_schema.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
GROUP BY TABLE_SCHEMA
ORDER BY total_gb DESC;`TABLE_ROWS` はInnoDBでは推定値です。行数を正確に知る必要がある表だけ `COUNT(*)` を取ってください。`index_gb` の比率が高い表は、後述する「ロード後にインデックスを作り直す」戦略の効果が大きい候補です。
- 対象
- SQL Server 2012 以降、Amazon RDS for SQL Server、Azure SQL Managed Instance
- 権限
- `VIEW DATABASE STATE`
- 変更作業
- なし(参照のみ)
- Production実行
- 可能
-- 対象: SQL Server 2012 以降(RDS / Azure SQL Managed Instance を含む)
-- 権限: VIEW DATABASE STATE
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
SCHEMA_NAME(t.schema_id) AS schema_name,
t.name AS table_name,
SUM(CASE WHEN ps.index_id IN (0, 1) THEN ps.row_count ELSE 0 END) AS row_count,
SUM(ps.reserved_page_count) * 8.0 / 1024 / 1024 AS reserved_gb,
SUM(ps.used_page_count) * 8.0 / 1024 / 1024 AS used_gb
FROM sys.dm_db_partition_stats AS ps
INNER JOIN sys.tables AS t
ON t.object_id = ps.object_id
GROUP BY t.schema_id, t.name
ORDER BY SUM(ps.reserved_page_count) DESC;ページサイズ8KBを前提にGB換算しています。`reserved_gb` は確保済み、`used_gb` は実使用です。差が大きい表は断片化や削除済み領域を含むため、移行後のサイズは移行元より小さくなることがあります(これも見積りではなく試験ロードで確認してください)。
- 対象
- MySQL 5.7 / 8.0、Aurora MySQL(mysqldump / mydumper)
- 権限
- 対象スキーマへの `SELECT`
- 変更作業
- なし(移行元は参照のみ)。ただし読み取り負荷がかかる
- Production実行
- 負荷を許容できる時間帯で実施すること
# 対象: MySQL 5.7 / 8.0、Aurora MySQL(mysqldump / mydumper)
# 権限: 対象スキーマへの SELECT
# 変更作業: なし(移行元は参照のみ)。ただし読み取り負荷がかかる
# Production 実行: 負荷を許容できる時間帯で実施すること
# 1) 単一テーブルで所要時間を実測する(--no-tablespaces は MySQL 8.0 で
# PROCESS 権限を要求されるのを避けるため)
time mysqldump \
--single-transaction \
--quick \
--no-tablespaces \
--host example-rds-endpoint \
--user sample_user \
--password \
SampleDB sample_table \
| gzip > /var/tmp/sample_table.sql.gz
# 2) 並列ダンプで実測する場合(資格情報はコマンドラインに書かず設定ファイルで渡す)
mydumper \
--defaults-file /etc/mysql/sample-migration.cnf \
--database SampleDB \
--threads 8 \
--rows 500000 \
--compress \
--outputdir /var/tmp/dump-sample
# 3) 出力サイズを確認し、テーブルサイズとの比率を記録する
du -sh /var/tmp/dump-sampleここで得た「このテーブルは何分かかり、出力は何GBだったか」だけが計画に載せてよい数字です。1テーブルの結果を全体へ外挿するときも、行の幅・インデックス数・BLOBの有無が違うテーブルでは比率が変わるため、性質の異なる代表テーブルを複数選んで測ってください。`--single-transaction` は一貫したスナップショットを取るためのオプションで、DDLが同時に走ると一貫性が崩れます。
- 対象
- MySQL 5.7 / 8.0、Aurora MySQL(移行元・移行先の双方)
- 権限
- 対象テーブルへの `SELECT`
- 変更作業
- なし(参照のみ)。ただし全行読み取りのため負荷がかかる
- Production実行
- 停止中または低負荷時間帯に実施すること
-- 対象: MySQL 5.7 / 8.0、Aurora MySQL(移行元・移行先の双方で同じSQLを実行する)
-- 権限: 対象テーブルへの SELECT
-- 変更作業: なし(参照のみ)。ただし全行を読むため I/O 負荷がかかる
-- Production 実行: 停止中または低負荷時間帯に実施すること
-- 1) 行数の一致を確認する(最も軽い検証。ここが合わなければ先へ進まない)
SELECT 'sample_table' AS table_name, COUNT(*) AS row_count
FROM SampleDB.sample_table;
-- 2) 主要列の値までを含めた突き合わせ(同一エンジン間の比較に使う)
SELECT
COUNT(*) AS row_count,
SUM(CRC32(CONCAT_WS('|', id, name, DATE_FORMAT(updated_at, '%Y-%m-%d %H:%i:%s')))) AS crc_sum
FROM SampleDB.sample_table;
-- 3) テーブル単位のチェックサム(全行を読む。大きな表では時間がかかる)
CHECKSUM TABLE SampleDB.sample_table EXTENDED;2) は移行元と移行先が同じエンジン系である場合の比較に使います。NULLの扱い、浮動小数点の表現、日時のフォーマットが揃っていないと一致しないため、`CONCAT_WS` で明示的に整形しています。異種DB間の移行では値の表現自体が変わるので、行数の一致とアプリケーション観点の検証(代表画面・代表バッチの結果比較)を主にしてください。
- 対象
- MySQL 5.7 / 8.0、Aurora MySQL
- 権限
- `information_schema` の参照権限
- 変更作業
- なし(参照のみ)
- Production実行
- 可能
-- 対象: MySQL 5.7 / 8.0、Aurora MySQL
-- 権限: information_schema の参照権限
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
-- 1) 直近に定義が変わったテーブル(凍結期間中に変更が入っていないかの確認に使う)
SELECT TABLE_SCHEMA, TABLE_NAME, CREATE_TIME, UPDATE_TIME
FROM information_schema.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
ORDER BY CREATE_TIME DESC;
-- 2) 二次インデックスの一覧(ロード後に作り直す対象の洗い出し)
SELECT
TABLE_SCHEMA,
TABLE_NAME,
INDEX_NAME,
GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) AS index_columns,
MAX(NON_UNIQUE) AS non_unique
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
AND INDEX_NAME <> 'PRIMARY'
GROUP BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME
ORDER BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME;2) の結果は、ロード前に二次インデックスを外し、ロード後に作り直す戦略を取る場合の作業一覧そのものになります。作り直しのDDLを事前に生成して保管しておくと、切り替え当日に定義を思い出す必要がなくなります。一意インデックス(`non_unique = 0`)は重複データの検出を兼ねるため、外す場合は重複が入らない保証を別途用意してください。
結果の読み方
| 列 | 意味 | 確認するポイント |
|---|---|---|
| TABLE_SCHEMA / TABLE_NAME | 対象スキーマとテーブル | 移行対象と対象外の線引きを、この一覧の上で明示する |
| estimated_rows | 推定行数(InnoDBでは統計に基づく概算) | 検証の基準にするなら `COUNT(*)` で実数を取り直す |
| data_gb | データ部分のサイズ | 転送量の主要部分。大きい順に試験実行の対象を選ぶ |
| index_gb | インデックス部分のサイズ | 比率が高い表ほど、ロード後にインデックスを作り直す方式の効果が大きい |
| free_gb / reserved-used の差 | 確保済みだが未使用の領域 | 移行先では解消されることが多い。移行先の必要容量は移行元の確保量より小さくなりうる |
| total_gb | データとインデックスの合計 | スキーマ単位で合計し、全体の「実サイズ」を確定させる |
| index_columns(二次インデックス一覧) | インデックスの構成列 | ロード後に再作成する対象の作業一覧になる |
| UPDATE_TIME | テーブル定義・データの更新時刻(エンジン依存) | 凍結期間中に想定外の変更が入っていないかの確認に使う |
こういう状況で使います
- 「何時間で終わるか」を聞かれたが、根拠のある数字を出せない
- 移行のリハーサルをしないまま日程だけが決まっている
- 許容停止時間が決まっていないのに、切り替え方式の議論が始まっている
- 初期ロードは終わったが、差分の追いつきが終わらない
- 移行先の容量を移行元と同じにしたら、ロード中に足りなくなった
- 切り戻す判断を誰がいつ下すのかが決まっていない
考えられる原因(可能性の高い順)
01
実サイズを測らずに「3TB」という総量だけで計画している
総量が同じでも、1つの巨大テーブルなのか、中規模テーブルが数千あるのかで作業性がまったく違います。オブジェクト単位のサイズと本数を先に確定させてください。
02
所要時間を一般的な目安から見積もっている
転送速度は回線帯域、ストレージのスループット、並列度、インデックスの有無、圧縮の有無で桁単位に変わります。他所の事例値を自環境に当てはめると、計画そのものが成立しません。
03
許容停止時間が先に決まっていない
切り替え方式は許容停止時間から決まります。停止できる時間が長ければ全停止方式が最も単純で確実です。逆算せずに方式を選ぶと、後から手戻りします。
04
インデックスをつけたままロードしている
二次インデックスを保持したままの一括ロードは、行の挿入ごとにインデックス更新が発生します。ロード後にまとめて作り直す方式と比べて所要時間が変わるため、両方を試験実行で比較してください。
05
検証方法を決めずに切り替え当日を迎えている
「動いているように見える」は検証ではありません。行数、値の突き合わせ、アプリケーション観点の確認のどれをどこまでやるかを、事前に合意しておく必要があります。
06
復帰不能点(point of no return)が定義されていない
新環境への書き込みが始まった後は、単純な切り戻しができなくなります。どの時点を過ぎたら前に進むしかないのかを、作業手順に明記してください。
確認手順
- 1
オブジェクト単位で実サイズと本数を測る
参照のみ上記の計測SQLを実行し、テーブル数・最大テーブルのサイズ・上位10件で全体の何割を占めるかを確定させます。
- 2
許容停止時間を関係者と確定させる
参照のみ技術的な検討の前に、業務として何時間止められるかを決めます。ここが決まらないと方式が決まりません。
- 3
性質の異なる代表テーブルを選んで試験実行する
中大きい表、行が幅広い表、BLOBを含む表、インデックスが多い表など、複数の性質を選んで所要時間を実測します。
- 4
移行先の実容量を試験ロードで確認する
中移行元の使用量と同じにはなりません。断片化の解消やストレージ構造の違いで増減します。
- 5
差分の発生量を測る
参照のみCDC方式を取る場合、初期ロード中に発生する変更量が追いつきの所要時間を決めます。日次の更新行数を実測してください。
- 6
リハーサルを本番同等の手順で1回以上通す
中手順書の抜けは、リハーサルでしか見つかりません。所要時間の実測値もここで確定します。
対応方法
すぐに実施できる低リスクの対応
対象の棚卸しを終わらせる
参照のみ移行するテーブル、移行しないテーブル、移行前に削除するテーブルを分けます。移行しないものを決めるだけで総量が減ることは珍しくありません。
許容停止時間から切り替え方式の候補を絞る
参照のみ長時間止められるなら全停止方式、短時間しか止められないなら初期ロード+CDC追いつき、止められないなら二重書き込みが候補になります。
事前検討が必要な変更
試験実行で所要時間を実測する
中代表テーブルの実測値から全体を積み上げます。目安値ではなく実測値だけを計画に載せてください。
インデックスと制約の扱いを決める
中二次インデックスと一部の制約をロード後に作り直す方式を、実測で比較して採否を決めます。再作成用のDDLは事前に生成して保管します。
検証の合格条件を文書化する
参照のみ行数一致、主要テーブルのチェックサム一致、代表画面・代表バッチの結果一致など、「何が揃えば切り替え完了とするか」を先に決めます。
凍結と周知の計画を作る
参照のみスキーマ変更・バッチ・データ投入をいつから止めるか、誰に周知するか、例外申請をどう扱うかを決めます。
再起動・サービス影響を伴う変更
初期ロードを実施する
高移行元に読み取り負荷、移行先に書き込み負荷がかかります。実測した所要時間に、想定外の再実行分を見込んだ余裕を持たせてください。
差分同期(CDC)を構成して追いつかせる
高差分の発生量が消化量を上回ると永遠に追いつきません。遅延が縮小しているかを継続的に確認します。
専門家のレビューが必要な作業
切り替え(カットオーバー)を実施する
専門家レビュー必須書き込み停止 → 差分の追いつき完了確認 → 検証 → 接続先切り替え → 監視強化、の順に、各段階の判断者と判断基準を決めたうえで実行します。
切り戻しを判断する
専門家レビュー必須合格条件を満たさなかった場合に、どこまで戻すのか(接続先だけか、データもか)を事前に決めておきます。復帰不能点を過ぎている場合は前進しか選べません。
!注意事項
- 所要時間の一般的な目安値は、この記事では示しません。回線、ストレージ性能、並列度、インデックス構成で桁単位に変わるためです。計画に載せてよい数字は、自環境での試験実行から得た実測値だけです。
- 1テーブルの実測値を全体へ外挿する場合、行の幅・インデックス数・BLOBの有無が異なる表では比率が変わります。性質の異なる代表テーブルを複数測ってください。
- 移行先の必要容量は、移行元の使用量と同じにはなりません。断片化の解消で減ることも、ストレージ構造の違いで増えることもあります。試験ロードで確認してください。
- 二次インデックスを外してロードする場合、一意インデックスも外すと重複データが入る可能性があります。重複が入らない保証を別途用意してください。
- `CHECKSUM TABLE` と全行のチェックサム計算は、テーブル全体を読み取ります。本番稼働中に大きな表へ実行しないでください。
- 復帰不能点を定義していない移行計画は、問題が起きたときに判断できません。切り戻しの条件・手順・判断者を、日程より先に決めてください。
- 凍結期間中のスキーマ変更は、初期ロード済みのデータと移行先の定義を食い違わせます。凍結の対象と例外の扱いを明文化してください。
バージョン・環境による違い
これで解決しない場合に確認すること
ネットワーク経路とその実効帯域を確認する
移行元と移行先の間の経路(専用線、VPN、インターネット)と実効帯域を、実際にデータを流して測ってください。カタログ値では計画できません。
移行先の一時領域とログ領域を確認する
ロード中はトランザクションログや一時領域が通常時より大きく伸びます。データ領域だけを見た容量計画は足りなくなります。
ロード中の移行元への影響を確認する
読み取り負荷でサービス側が遅くなることがあります。並列度を落とす、時間帯を分ける、レプリカから読む、などの選択肢を検討してください。
文字セット・照合順序・タイムゾーンの扱いを確認する
移行の前後で値の表現が変わると、検証で不一致が出ます。移行前に基準を決めてください。
権限・接続情報・監視設定の移行を計画に含める
データが移っても、ユーザー、権限、監視、バックアップの設定は自動では移りません。これらの作業時間も日程に含めてください。
関係者への周知と問い合わせ窓口を決める
凍結期間、切り替え時刻、影響範囲、問い合わせ先を事前に周知します。当日の混乱の多くはここで防げます。
この文書の根拠と限界
一般的な技術説明
MySQLの `information_schema.TABLES` とSQL Serverの `sys.dm_db_partition_stats` の公開仕様、および `mysqldump` / `mydumper` の公開されたオプション仕様に基づく、一般的な移行計画の立て方です。所要時間・転送速度・容量比などの数値は環境に強く依存するため、意図的に記載していません。特定顧客の移行事例は含みません。
よくある質問
3TBの移行にはどれくらい時間がかかりますか?
この記事では数字を示しません。所要時間は回線の実効帯域、移行元と移行先のストレージ性能、並列度、インデックス構成、圧縮の有無で桁単位に変わるためです。代表テーブルで試験実行し、その実測値から積み上げてください。他所の事例値を自環境に当てはめると計画が成立しません。
どの切り替え方式を選べばよいですか?
許容停止時間から決めます。長時間止められるなら全停止方式が最も単純で検証しやすく、短時間しか止められないなら初期ロード+CDC追いつき、ほぼ止められないなら二重書き込みが候補です。後の2つは停止時間と引き換えに、CDC運用やアプリケーション改修という作業が増えます。
Productionで実行できますか?
サイズ計測と定義の棚卸しSQLは参照専用で、本番でも実行できます。試験ダンプとチェックサム計算は読み取り負荷がかかるため、時間帯を選んでください。初期ロードと切り替えは計画作業として、事前に合意した手順で実施します。
インデックスはロード前と後のどちらで作るべきですか?
一般論では決められないため、両方を試験実行で比較してください。二次インデックスをロード後に作り直す方式が有利になることは多いですが、再作成そのものに時間がかかるため、合計時間で判断する必要があります。一意インデックスを外す場合は、重複データが入らない保証を別に用意してください。
検証はどこまでやれば十分ですか?
「何が揃えば完了とするか」を事前に合意した内容が基準です。最低限は全対象テーブルの行数一致、加えて主要テーブルの値の突き合わせ、そして代表的な画面・バッチの結果が移行前と一致することを確認します。全件の値照合は時間がかかるため、対象と範囲を決めて実施してください。
切り戻しはいつまで可能ですか?
新環境への書き込みが始まるまでです。それ以降は新環境にしか存在しないデータが生まれるため、単純に旧環境へ戻すとデータを失います。この境界を復帰不能点として手順書に明記し、通過の判断を誰が行うかを決めてください。
この文書がカバーする質問
- 大規模データベースの移行にかかる時間をどう見積もるか
- データベース移行の切り替え方式の選び方
- 移行後のデータ整合性をどう検証するか
- 移行先のストレージ容量をどう見積もるか
リスク表示の意味
- 参照のみデータと設定を変更しません。
- 低影響は限定的ですが、権限と負荷の確認が必要です。
- 中性能・ロック・コストに影響する可能性があります。
- 高障害・データ損失・復旧作業が発生する可能性があります。
- 専門家レビュー必須本番適用前に別途レビューが必須です。
GIIPの対応範囲
移行計画そのものは、実測とレビューを重ねれば作れます。実務で抜けやすいのは、切り替えた後の数週間です。GIIPでは、切り替え前に取得した主要指標(代表クエリの実行時間、エラー率、ストレージ使用量の推移)を基準線として保存し、切り替え後に同じ指標を並べて差分を追跡しています。差が出たものだけを対応対象として切り出し、日々の比較と一次調査はAIエージェントが、切り戻しや構成変更の判断は人が行う分担にしています。
執筆・技術検証
GIIP プロダクション運用チーム
大規模Webサービス、SQL Server、Oracle、AWS、Azureの設計・移行・運用に約30年従事。x12largeクラスのAWS RDS for SQL Server環境12セット、約12万テーブルのOracle環境、約3TBのTiDBからAurora MySQLへの移行を経験。現在も複数のクラウドデータベースと約30のWebサービスを、AIエージェントと人間の専門家が継続的に監視・運用しています。
TiDBからAurora MySQLへ移行するときに確認する項目
TiDBはMySQL互換ですが同一ではありません。主キー・採番・トランザクション・統計・容量の各差分を、確認用SQLとともに移行前チェックリストとして整理します。
aurora-mysqlAWS DMSでError 1032が発生する原因と確認方法
DMSのCDCで出るError 1032はターゲットに該当行が無いという意味です。制御テーブルの読み方と主キー不一致の確認手順、タスク設定の選択肢を整理します。
aurora-mysqlAurora MySQLでutf8mb3からutf8mb4へ移行するときに確認すること
utf8mb4への変換で最初に壊れるのはインデックスのキー長です。対象の洗い出しSQL、照合順序の選び方、変換時の影響と設定箇所をまとめます。
awsAWS RDSで大きいインスタンス1台と小さいインスタンス複数台に分ける場合の違い
RDSのサイジングで「大きい1台」と「小さい複数台」を比べるときの技術的な差分と、決める前に測るべきCloudWatch指標を整理した文書です。
関連サービス
3TB級移行の計画レビューを依頼する
同じ確認を複数の環境で継続する必要がある場合は、運用体制ごと相談できます。
3TB級移行の計画レビューを依頼する