問題の発生テーブルの複製やクエリ結果の保存に CREATE TABLE ... SELECT (CTAS) ショートカットを使用しようとして、壁にぶつかることがあります。このコマンドは手軽なバックアップ手法として開発者に好まれますが、現代の高可用性環境では失敗します。MySQLインスタンスでグローバルトランザクションID (GTID) が使用されている場合(AWS RDS、Aurora、または堅牢なマスター・スレーブ構成では標準的です)、以下のエラーが表示されます。
ERROR 1785 (HY000): Statement violates GTID consistency: CREATE TABLE ... SELECT.
これはMySQLがデータを保護しているためです。MySQLは、クラスタ全体ですべての変更を追跡し、サーバー間でデータの不一致(ドリフト)が発生しないよう厳格なルールを適用しています。
原因サーバーがこの厳格なモードになっているか確認するには、以下のコマンドを実行します。
SHOW VARIABLES LIKE 'enforce_gtid_consistency';
結果が ON の場合、MySQLはトランザクションのログ記録に対して非常に厳格になります。CREATE TABLE ... SELECT ステートメントが問題となるのは、新しいスキーマの定義 (DDL) と、行の挿入 (DML) という2つの異なる処理を一度に行おうとするためです。
MySQL 8.0.21より前のバージョンでは、これら2つの異なるアクションを単一のアトミックなGTIDイベントとしてログに記録することができません。マスターサーバーが処理の途中でクラッシュしたり、レプリカで遅延が発生したりした場合、クラスタ内のすべてのノードで新しいテーブルが全く同じ状態になることを保証できないのです。この不整合を防ぐため、MySQLはこのコマンドをブロックします。
解決策:2つのステップに分割する解決策は単純です。すべての処理を1行で行うのをやめるだけです。操作を分割することで、GTIDエンジンがレプリケーションを壊すことなくログに記録できる、明確なステップを提供します。
1. テーブル構造を定義するまず、空の枠組みを作成します。既存のテーブルを(インデックスを含めて)正確にコピーしたい場合は LIKE 句を使用します。特定のカラムのみが必要な場合は、手動で定義します。
-- オプションA: 正確な構造をクローンする(推奨)
CREATE TABLE orders_backup LIKE orders;
-- オプションB: 特定のデータ用にカスタム構造を作成する
CREATE TABLE monthly_summary (
id INT PRIMARY KEY,
total_sales DECIMAL(10,2),
report_date DATE
);
2. データを移行するテーブルが作成されたら、標準的な INSERT INTO ... SELECT ステートメントを使用してデータを移動します。これは純粋なデータ操作(DML)であるため、GTID環境でも問題なく処理されます。
INSERT INTO monthly_summary (id, total_sales, report_date)
SELECT id, amount, '2023-12-31'
FROM orders
WHERE status = 'completed' AND created_at >= '2023-12-01';
100万行を超えるような大規模なデータセットの場合、元のテーブルを長時間ロックしないよう、LIMIT を追加したりバッチ処理でデータを処理したりすることを検討してください。
結果の確認分割したコマンドを実行した後、すべてが同期されているか30秒ほどかけて確認しましょう。
- **行数の確認:** 数値が期待通りか確認します。
```
SELECT COUNT(*) FROM monthly_summary;
- **レプリケーションの状態を確認:** 本番環境のマスターで作業している場合は、レプリカが正常に動作しているか確認してください。
```
SHOW REPLICA STATUS\G;
`Replica_IO_Running: Yes` と `Replica_SQL_Running: Yes` を探します。これらが `No` になっている場合は、別の大きなレプリケーションの問題が発生している可能性があります。
ベストプラクティス
- **スクリプトで CTAS を使用しない:** 自動化された移行スクリプトやアプリケーションコード内で `CREATE TABLE ... SELECT` を使用するのは避けましょう。GTIDが有効な環境に移行した瞬間にエラーとなる「時限爆弾」になります。
- **一時テーブルに注意:** `CREATE TEMPORARY TABLE` には注意が必要です。GTIDの一貫性が保たれている環境では、通常、トランザクション内(`BEGIN` と `COMMIT` の間)で一時テーブルを作成することはできません。
- **可能であればアップグレードを:** MySQL 8.0.21 で「アトミック DDL」が導入され、InnoDBテーブルにおいてGTID環境下での CTAS がついに許可されました。5.7 や初期の 8.0 バージョンを使用している場合は、アップグレードすることでこの問題を根本から解消できます。

