MySQL에서 외래 키 제약 조건을 일시적으로 비활성화하는 방법은 무엇입니까?


651

MySQL에서 제약 조건을 일시적으로 비활성화 할 수 있습니까?

두 개의 장고 모델이 있는데, 각각 다른 하나에 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

3
FK를 삭제하고 다시 적용하면 DB 가 변경됩니다. 당신은 시스템이 어떤 의미를 볼 수 있도록하는 매우 제약을 무시하려고 노력하고 있으며, FK가 일시적 일 수 있다는 것을 고려하지 않으며, 그것이 알고 있다면 그것이 당황 할 것입니다.
— 그랜트 토마스

1
당신이하려는 일이 이상합니다. 그러나 어떤 데이터베이스를 사용하고 있습니까?
— andrefsp

4
제약 조건을 비활성화하는 대신 영구적으로 수정 한 경우 ON DELETE SET NULL어떻게 해야 합니까? 그것은 비슷한 일을 할 것이고 키 검사를 켜고 끌 필요가 없습니다.
— dnagirl

1
@ dnagirl : 실제로 더 좋을 것입니다. 어떻게해야합니까?
— jul

답변:


1466

시도 DISABLE KEYS또는

SET FOREIGN_KEY_CHECKS=0;

확인

SET FOREIGN_KEY_CHECKS=1;

후.


14
이것은 전체 또는 그 세션으로 mysql에 설정된 것입니까?
— tipu

28
세션 당이라고 생각합니다.
— 앤드류 캠벨

13
serverfault.com/questions/291100/...는 , 또한 당신이주의 할 수 없습니다 disable keys 이노 디비 위해 할
— Pacerier

1
단일 테이블에 대해 FOREIGN_KEY_CHECKS를 비활성화 할 수 있습니까?
— jDub9

@Pacerier 그것을 읽었을 때, 당신은 할 수 있지만 단일 세션에 대해서만 나타납니다.
— Brett

150

외래 키 제약 조건을 전체적으로 끄려면 다음을 수행하십시오.

SET GLOBAL FOREIGN_KEY_CHECKS=0;

완료되면 다시 설정해야합니다.

SET GLOBAL FOREIGN_KEY_CHECKS=1;

경고 : 단일 사용자 모드 유지 관리를 수행 할 때만이 작업을 수행해야합니다. 데이터 불일치가 발생할 수 있습니다. 예를 들어, mysqldump 출력을 사용하여 많은 양의 데이터를 업로드 할 때 매우 유용합니다.


1
이것이 내가 알아야 할 것이므로, 좋은 연습은 아니지만,이 사람들의 대답은 더 높은 점수를 받아야합니다 ...
— ftrotter

1
'최고의 답변'을 시도한 후에도 효과가 없었습니다. 아마도 차이점에 대한 설명이 추가 될 수 있습니다.
— hexnet

7
@hexnet의 차이는 단지 것입니다 SET FOREIGN_KEY_CHECKS단지에 대한 값 변경 현재 연결을 하는 동안 SET GLOBAL ..의 값을 변경하는 모든 연결 미래의 연결을 포함. SET FOREIGN..하나의 창 에서만 작업 하고 다른 연결에서 다른 창에 명령문을 적용하려고하면 값이 변경되지 않습니다. 를 사용 GLOBAL하면 동일한 변수가 두 연결 모두에 대해 동일한 값을 갖습니다.
— MatsLindh

더 큰 덤프 (6GB 이상)를 재생할 때 나를 도울 수있는 유일한 것은 <3
— 최대

이것은 나를 위해 작동하지 않습니다. 시도하면 다음과 같이 표시됩니다.ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
— Mike 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

원격 열 유형을 변경할 때 참조가 중단되지 않습니까? (고객이 수정 된 임시 테이블의 이름을 원래 테이블 이름으로
— 바꾸는

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 명령을 건너 뛰고 확인란의 선택을 취소 할 수 있습니다.
— Jan

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에서 경고가 발생하며, DISABLE KEYS 명령을 실행할 때 InnoDB 엔진에이 옵션이 없습니다.
— jDub9

이 작업은 alter table 없이도 작동하지 않았습니다.
— David Kabii

3

키 필드가 널 입력 가능하면 삭제하기 전에 값을 널로 설정할 수도 있습니다.

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으로 설정하는 것은 좋지 않습니다. 그렇게하면 데이터베이스가 참조 무결성을 위반하지 않도록하지 않기 때문입니다. 이로 인해 부정확하거나 오해의 소지가 있거나 불완전한 데이터가 발생할 수 있습니다.

자식 열의 모든 값이 부모 열의 값과 같아야하기 때문에 외래 키를 만듭니다. 외래 키 제약 조건이 없으면 자식 행에 부모 행에없는 값이있을 수 있으며 이로 인해 데이터가 정확하지 않을 수 있습니다.

예를 들어, 학생이 로그인 할 수있는 웹 사이트가 있고 모든 학생이 계정을 사용자로 등록해야한다고 가정 해 봅시다. 사용자 ID를 기본 키로 사용하여 하나의 사용자 ID 테이블이 있습니다. 학생 ID가 열인 학생 계정을위한 또 다른 테이블. 모든 학생은 사용자 ID를 가져야하므로 학생 계정 테이블의 학생 ID를 사용자 ID 테이블의 기본 키 사용자 ID를 참조하는 외래 키로 만드는 것이 좋습니다. 외래 키 확인이 없으면 학생은 학생 ID와 사용자 ID를 갖지 못하게 될 수 있습니다. 이는 학생이 사용자가 아닌 계정을 얻을 수 있음을 의미합니다.

많은 양의 데이터가 발생한다고 상상해보십시오. 그렇기 때문에 외래 키 검사가 필요합니다.

오류의 원인을 파악하는 것이 가장 좋습니다. 하위 행에서 삭제하지 않고 상위 행에서 삭제하려고합니다. 부모 행에서 삭제하기 전에 자식 행에서 삭제하십시오.


사실, 항상 절충안이 있습니다.
— Pacerier

21
아무도 이렇게 영원히 그것을 말하고 있지 않습니다. 구속 조건을 끄고 일부 데이터를 대량로드 한 다음 다시 켭니다. 별거 아니에요 사람들은 항상 그렇게 해요
— bwawok

대량 가져 오기가 필요하고, 성능은 최소한 매우 일반적입니다. 또한 때로는 데이터를 복원하기 만하면 확인이 가능합니다.
— Firas Abd Alrahman

3
이것은 질문에 대한 답변이 아닙니다.
— Koray Tugay

그의 질문은 이것을 일시적으로 수행하는 방법입니다. 특정 유지 보수 및 데이터 가져 오기를 수행 할 때 필요합니다. 물론주의해야 할 점은 가져 오기 스크립트가 데이터 무결성을 책임진다는 것입니다. 그런 다음 나중에 인덱스와 제약 조건을 다시 설정하면 db에서 무언가가 손상되었는지 알려줍니다.
— mcstar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.