web-dev-qa-db-ja.com

外部キー参照を更新せずにInnoDBテーブルの名前を変更しますか?

InnoDBテーブルを新しいテーブルに置き換えようとしていますが、古いテーブルを指すすべての外部キー参照が新しいテーブルを指すようにします。

だから私はこれを試しました:

SET foreign_key_checks = 0;
ALTER TABLE foo RENAME foo_old;
ALTER TABLE foo_new RENAME foo;

残念ながら、foreign_key_checksが無効になっている場合でも、fooを指すすべての参照はfoo_oldを指すように変更されます。今私はどちらかを探しています

  • テーブル全体を再構築せずに外部キー参照を元に戻す方法、または
  • 外部キー参照を更新せずにテーブルの名前を変更する方法。

外部キーを削除して再作成してみましたが、テーブルが大きいため数時間かかります。テーブルを置き換えることの全体的なポイントは、限られたダウンタイムでスキーマを変更することでした。

32
Bart van Wissen

古い質問ですが、次の方法が考えられます。基本的に、テーブルの名前を変更するのではなく、データを移動します。もちろん、新しいデータが外部キー規則に準拠していることを確認する必要があります。

SET foreign_key_checks = 0;
CREATE TABLE IF NOT EXISTS foo_old LIKE foo;
INSERT INTO foo_old SELECT * FROM foo;
TRUNCATE foo;
INSERT INTO foo SELECT * FROM foo_new;

これを1つのクエリとして実行して、foreign_key_checksがすべてに適用されるようにしてください。お役に立てれば。

11
xelber

MySQL 5.6では、innodb_file_per_table=ONを使用すると、表スペースをその場で交換できます。ファイル操作は個別に実行する必要があるため、SQLを使用してこれを完全に実行することはできません。まず、コピーするfoo_newテーブルを準備し、fooデータをドロップします。

SET foreign_key_checks = 0;
ALTER TABLE foo DISCARD TABLESPACE;
FLUSH TABLES foo_new FOR EXPORT;

この時点で、関連するInnoDBファイルを正しい名前にコピーする必要があります。ファイルはデータディレクトリに保存されます。たとえば、Debianでは、デフォルトで/var/lib/mysql/yourdatabaseにあり、ファイルはfoo_new.ibdfoo_new.cfg、およびfoo_new.frmです。それらをそれぞれfoo.ibdfoo.cfg、およびfoo.frmにコピーします。例えば:

$ cp foo_new.ibd foo.ibd
$ cp foo_new.frm foo.frm
$ cp foo_new.cfg foo.cfg

MySQLが新しいファイルにアクセスできることに注意してください(たとえば、正しい所有者、アクセス権があります)。完了したら、テーブルを再度インポートして、外部キーを有効にすることができます。

UNLOCK TABLES;
ALTER TABLE foo IMPORT TABLESPACE;
SET foreign_key_checks = 1;

これは、foo_newfooにコピーするだけです。 foofoo_oldにコピーする必要がある場合は、手順を繰り返します。

7
vhu

残念ながら、最初に外部キーを削除して再作成しない限り、問題を回避する方法はないと思います。

これはマイナーですが、RENAMEコマンドでも何かを見つけました。それらをチェーン化することができ、すべてのステップが成功しない限り、他のすべての名前変更がロールバックされます。構文は次のとおりです。

RENAME TABLE foo TO foo_old, foo_new TO foo;
7
James C

InnoDBは外部キーでテーブルの内部ポインターを使用するため、このテーブルに付けられた名前に関係なく(RENAMEを使用)、SET foreign_key_checks = 0を使用する場合も含めて制約が保持されます。

テーブル全体を再構築せずに外部キー参照を元に戻す方法

innodb_file_per_table=ONを使用すると、最も近い方法になります(@vhuの回答を参照)。

外部キー参照を更新せずにテーブルの名前を変更する方法。

ダウンタイムと労力を最小限に抑え、サーバーへのシェルアクセスを必要としないソリューションは、単に2つのデータベースを操作し、それらを期限内にオンにすることです、データが変更されない場合とても

大きなテーブル以外のすべてのテーブルを同期するか、変更がある場合はスイッチまでアプリケーションでmysqlコマンド(削除、更新、挿入)を一時的に複製する方がさらに高速になる可能性があります。

5
Adam

これを回避する方法を見つけました...名前を変更する代わりに、ソーステーブルを削除するだけです。

この例では、テーブルを「mytbl」と呼びます。

  1. ソーステーブルのコピーを作成します。例: 'mytbl_new'
  2. データを新しいテーブルにコピーします
  3. ソーステーブル 'mytbl'を削除します
  4. 「mytbl_new」の名前を「mytbl」に変更します

唯一の欠点は、元のテーブルのバックアップを保持できないことですが、事前にmysqldumpすることはできます。または、元のテーブルの逐語的なコピーが必要な場合は、追加のテーブルコピーを作成できます。

2
Jim Backus