MySQLで外部キー制約を一時的に無効にする方法は?


651

MySQLの制約を一時的に無効にすることは可能ですか?

2つのDjangoモデルがあり、それぞれに他のモデルへのForeignKeyがあります。モデルのインスタンスを削除すると、ForeignKey制約のためにエラーが返されます。

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()  #a foreign key constraint fails here

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

一時的に制約を無効にして、とにかく削除することは可能ですか?


3
私があなたがやりたいことを理解していないか、あなたがやろうとしていることが非常に醜いです。たとえそれができるとしても、おそらくすべきではないでしょう。
Dariusz 2013年

3
FK を削除して再適用すると、データベース変更されます。あなたは、システムが何らかの意味を見るのを可能にするまさにその制約に逆らおうとしている、それはFKが一時的なものである可能性があることを考慮しておらず、もし知っていれば、それはパニックになるだろう。
Grant Thomas

1
あなたがやろうとしていることは奇妙です。しかし、どのデータベースを使用していますか?
andrefsp 2013年

4
制約を無効にするのではなく、永久に変更した場合はON DELETE SET NULLどうなりますか?それでも同様のことができ、キーのチェックをオンまたはオフにする必要はありません。
dnagirl 2013年

1
@dnagirl:それは確かに良いでしょう。どうやってやるの?
2013年

回答:


1466

試すDISABLE KEYS

SET FOREIGN_KEY_CHECKS=0;

確認してください

SET FOREIGN_KEY_CHECKS=1;

あと。


14
これはmysql全体として設定されているものですか、それともそのセッションだけですか?
tipu 2013年

28
セッションごとだと思います。
Andrew Campbell

13

1
単一のテーブルに対してFOREIGN_KEY_CHECKSを無効にすることはできますか?
jDub9 2018

@Pacerierそれを読んで、それはあなたができるようですが、単一のセッションのためだけです。
ブレット

150

外部キー制約をグローバルにオフにするには、次のようにします。

SET GLOBAL FOREIGN_KEY_CHECKS=0;

終わったら忘れずに戻してください

SET GLOBAL FOREIGN_KEY_CHECKS=1;

警告:これは、シングルユーザーモードのメンテナンスを行う場合にのみ実行してください。データの不整合が発生する可能性があるため。たとえば、mysqldump出力を使用して大量のデータをアップロードする場合に非常に役立ちます。


1
これは私が知る必要があったので、それは素晴らしい習慣ではありませんが、この連中の答えはより高い得点になるはずです...
ftrotter

1
「ベストアンサー」を試してもうまくいかなかったので、これはうまくいきました。おそらく、違いの説明を追加できます。
hexnet 2015

7
@hexnetの違いはSET FOREIGN_KEY_CHECKS現在の接続の値を変更するだけで、将来の接続を含むすべての接続SET GLOBAL ..の値を変更することです。あるウィンドウでのみ実行し、別のウィンドウで(別の接続を介して)ステートメントを適用しようとした場合、値はそこで変更されていません。を使用すると、両方の接続で同じ変数の値が同じになります。SET FOREIGN..GLOBAL
MatsLindh

私を助けることができる唯一のことは、大きなダンプ(6+ GB)<3再生時
最大

これは私にはうまくいきません。私がしようとしたとき、私は以下を参照してくださいERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
マイク・B

53

私は通常、テーブルを切り捨てたいときにのみ外部キー制約を無効にします。この答えに戻り続けるので、これは将来の私のためです:

SET FOREIGN_KEY_CHECKS=0;
TRUNCATE TABLE table;
SET FOREIGN_KEY_CHECKS=1;

25

制約を無効にする代わりに、恒久的にON DELETE SET NULLに変更します。それでも同様のことができ、キーのチェックをオンまたはオフにする必要はありません。そのようです:

ALTER TABLE tablename1 DROP FOREIGN KEY fk_name1; //get rid of current constraints
ALTER TABLE tablename2 DROP FOREIGN KEY fk_name2;

ALTER TABLE tablename1 
  ADD FOREIGN KEY (table2_id) 
        REFERENCES table2(id)
        ON DELETE SET NULL  //add back constraint

ALTER TABLE tablename2 
  ADD FOREIGN KEY (table1_id) 
        REFERENCES table1(id)
        ON DELETE SET NULL //add back other constraint

これ(http://dev.mysql.com/doc/refman/5.5/en/alter-table.html)とこれ(http://dev.mysql.com/doc/refman/5.5/en)を読んでください。/create-table-foreign-keys.html)。


7
テーブルの変更には長い時間がかかる可能性があることに注意してください。サーバーのグローバルFOREIGN_KEY_CHECKSを0 に設定し、ダーティな作業が完了したら元に戻すことをお勧めします。その上、それはあなたのテーブルを書くためにロックするかもしれません。
Aki

リモート列タイプを変更するときに参照が壊れませんか?(私のクライアントは、変更された一時テーブルの名前を元のテーブル名に変更しているようです。)
Cees Timmerman

15

外部キー制約をグローバルにオフにするには:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

およびアクティブな外部キー制約の場合

SET GLOBAL FOREIGN_KEY_CHECKS = 1;

10

phpmyadminを使用した非常にシンプルなソリューション:

  • テーブルでSQLタブに移動します
  • 実行するSQLコマンドを編集すると、「外部キーチェックを有効にするGO」というチェックボックスがの横に表示されます
  • このチェックボックスをオフにして、SQLを実行します。実行後、自動的に再チェックされます。

3
ありがとう!SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;PHPMyAdminでは、「外部キーのチェックを有効にする」チェックボックスをオフにするのを忘れたため、実際にはソリューションが機能しませんでした。PHPMyAdminでは、これらのSETコマンドをスキップして、チェックボックスをオフにすることができます。
1

5

私にとってSET FOREIGN_KEY_CHECKS=0;は十分ではありませんでした。私はまだ持っていましたcom.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException

追加しなければならなかったALTER TABLE myTable DISABLE KEYS;

そう:

SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE myTable DISABLE KEYS;
DELETE FROM myTable;
ALTER TABLE myTable ENABLE KEYS;
SET FOREIGN_KEY_CHECKS=1;

ちなみに、mySQL 5.7は警告をスローします。DISABLEKEYSコマンドを実行する場合、InnoDBエンジンにはこのオプションがありません。
jDub9

これは機能しましたが、alterテーブルがないと機能しませんでした
David Kabii

3

キーフィールドがnullに対応している場合は、削除する前に値をnullに設定することもできます。

cursor.execute("UPDATE myapp_item SET myapp_style_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed() 

cursor.execute("UPDATE myapp_style SET myapp_item_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

2

phpMyAdminでは、複数の行を選択してから、削除アクションをクリックできます。削除クエリを一覧表示する画面が表示されます。外部キーのチェックをオフにし、[はい]をクリックして実行します。

これにより、ON DELETE制限の制約がある場合でも、行を削除できます。


-2

外部キー制約を0に設定することはお勧めできません。そうすると、データベースは参照整合性に違反していないことを保証しないためです。これは、不正確、誤解を招く、または不完全なデータにつながる可能性があります。

子列のすべての値は親列の値と同じでなければならないため、外部キーを作成します。外部キー制約がない場合、子行には親行にない値が含まれる可能性があり、データが不正確になる可能性があります。

たとえば、学生がログインするためのWebサイトがあり、すべての学生がユーザーとしてアカウントに登録する必要があるとします。ユーザーIDを主キーとするユーザーIDのテーブルが1つあります。そして、学生IDを列として持つ学生アカウント用の別のテーブル。すべての学生はユーザーIDを持っている必要があるため、学生アカウントテーブルの学生IDを、ユーザーIDテーブルの主キーユーザーIDを参照する外部キーにすることは理にかなっています。外部キーのチェックがない場合、学生は学生IDとユーザーIDを持たなくなる可能性があります。つまり、学生はユーザーでなくてもアカウントを取得できますが、これは誤りです。

大量のデータが発生した場合を想像してみてください。そのため、外部キーのチェックが必要です。

エラーの原因を突き止めるのが最善です。おそらく、子行から削除せずに親行から削除しようとしています。親行から削除する前に、子行から削除してください。


確かに、常にトレードオフがあります。
Pacerier 2015

21
誰もこのように永遠に実行するように言っているのではありません。制約をオフにし、一部のデータを一括でロードして、オンに戻します。大したことではありません、人々はいつもそれをします。
bwawok 2015年

一括インポートには必要ですが、少なくともパフォーマンスには非常に一般的です。また、場合によっては、データを復元する必要があるだけで、チェックを行うことができます。
Firas Abd Alrahman 2017

3
これは質問に対する答えではありません。
Koray Tugay

注、彼の質問はこれを一時的に行う方法です。これは、特定のメンテナンスとデータのインポートを行うときに必要です。もちろん、注意点は、インポートスクリプトがデータの整合性に責任を持つことです。その後、インデックスと制約が再びオンになると、何かが壊れているかどうかがデータベースから通知されます。
mcstar 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.