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.