외래 키 제약 조건 : ON UPDATE 및 ON DELETE 사용시기


195

MySQL Workbench를 사용하여 데이터베이스 스키마를 설계하고 있습니다.

어쨌든, 나는 외래 키 지원 때문에 InnoDB를 사용하기로 결정했습니다. 그래도 한 가지 주목할 점은 외래 키에 대해 업데이트시 및 삭제 옵션을 설정할 수 있다는 것입니다. 간단한 예에서 "제한", "캐스케이드"및 널 설정 위치를 설명 할 수 있습니까?

예를 들어, user을 포함하는 테이블이 있다고 가정 해보십시오 userID. 그리고 message2 개의 외래 키 ( 테이블 userID에서 동일한 기본 키를 참조)가있는 다 대다 메시지 테이블 이 있다고 가정 해보십시오 user. 이 경우 업데이트시 및 삭제시 옵션을 설정하는 것이 유용한가요? 그렇다면 어느 것을 선택합니까? 이것이 좋은 예가 아니라면, 이것이 어떻게 유용 할 수 있는지 보여주는 좋은 예를 제시해 주시겠습니까?

감사

답변:


485

데이터베이스에 제한을 두는 것을 망설이지 마십시오. 일관성있는 데이터베이스가 있어야하며 이것이 데이터베이스를 사용해야하는 좋은 이유 중 하나입니다. 특히 여러 응용 프로그램이 요청하는 경우 (또는 하나의 응용 프로그램이지만 직접 소스와 다른 소스를 사용하는 배치 모드).

MySQL을 사용하면 postgreSQL에서와 같이 고급 제약 조건이 없지만 적어도 외래 키 제약 조건은 상당히 고급입니다.

이 회사의 사람들을 포함하는 사용자 테이블이있는 회사 테이블을 예로 들어 보겠습니다.

CREATE TABLE COMPANY (
     company_id INT NOT NULL,
     company_name VARCHAR(50),
     PRIMARY KEY (company_id)
) ENGINE=INNODB;

CREATE TABLE USER (
     user_id INT, 
     user_name VARCHAR(50), 
     company_id INT,
     INDEX company_id_idx (company_id),
     FOREIGN KEY (company_id) REFERENCES COMPANY (company_id) ON...
) ENGINE=INNODB;

ON UPDATE 절을 살펴 보자 .

  • ON UPDATE RESTRICT : 기본값 : COMPANY 테이블에서 company_id를 업데이트하려고하면 한 명의 사용자가이 회사에서 최소한 링크하면 엔진이 조작을 거부합니다.
  • 업데이트시 조치 없음 : RESTRICT와 동일합니다.
  • ON UPDATE CASCADE : 가장 좋은 방법 : COMPANY 테이블 행에서 company_id를 업데이트하면 엔진은이 COMPANY를 참조하는 모든 USER 행에서 그에 따라 업데이트합니다 (그러나 USER 테이블에서 활성화 된 트리거는 없습니다). 엔진이 변경 사항을 추적합니다. 좋습니다.
  • ON UPDATE SET NULL : COMPANY 테이블 행에서 company_id를 업데이트하면 엔진은 관련 USERs company_id를 NULL로 설정합니다 (USER company_id 필드에서 사용 가능해야 함). 업데이트와 관련하여 흥미로운 일을 볼 수는 없지만 잘못되었을 수 있습니다.

그리고 이제 ON DELETE 쪽에서 :

  • ON DELETE RESTRICT : 기본값 : COMPANY 테이블에서 company_id ID를 삭제하려고하면 한 명의 사용자가이 회사의 링크를 하나 이상 연결하면 생명을 구할 수있는 경우 엔진이 작업을 거부합니다.
  • 삭제 조치 없음 : RESTRICT와 동일
  • ON DELETE CASCADE : 위험 : COMPANY 테이블에서 회사 행을 삭제하면 엔진과 관련 사용자가 삭제됩니다. 이것은 위험하지만 보조 테이블에서 자동 정리를 수행하는 데 사용할 수 있습니다 (따라서 원하는 것이 될 수는 있지만 COMPANY <-> USER 예에서는 확실히 아닙니다)
  • ON DELETE SET NULL : handful : COMPANY 행을 삭제하면 관련 USER는 자동으로 NULL과 관계가 있습니다. Null이 회사가없는 사용자에게 귀하의 가치 인 경우, 이는 좋은 행동이 될 수 있습니다. 예를 들어, 일부 컨텐츠의 작성자로서 사용자를 애플리케이션에 유지해야하지만 회사를 제거하는 것은 문제가되지 않습니다.

일반적으로 내 기본값은 ON DELETE RESTRICT ON UPDATE CASCADE 입니다. 일부 ON DELETE CASCADE는 트랙 테이블 (모든 로그가 아닌 로그 등)과 ON DELETE SET NULL마스터 테이블이 USER 테이블의 JOB 테이블과 같이 외래 키를 포함하는 테이블의 '간단한 속성'인 경우입니다.

편집하다

내가 쓴지 오래되었습니다. 이제 중요한 경고 하나를 추가해야한다고 생각합니다. MySQL에는 캐스케이드와 관련하여 문서화 된 한 가지 큰 제한이 있습니다. 캐스케이드는 트리거를 발생시키지 않습니다 . 따라서 엔진을 사용하여 트리거를 사용할 정도로 확신이 많으면 계단식 제약 조건을 피해야합니다.

MySQL 트리거는 SQL 문으로 테이블을 변경 한 경우에만 활성화됩니다. 뷰의 변경이나 SQL 문을 MySQL 서버로 전송하지 않는 API에 의한 테이블 변경에 대해서는 활성화되지 않습니다.

==> 마지막 수정 사항을 아래에서보십시오.

외래 키 동작으로 트리거가 활성화되지 않습니다.

그리고 나는 이것이 언젠가 고쳐질 것이라고 생각하지 않습니다. 외래 키 제약 조건은 InnoDb 스토리지에서 관리하고 트리거는 MySQL SQL 엔진에서 관리합니다. 둘 다 분리되어 있습니다. Innodb는 제약 조건 관리 기능이있는 유일한 스토리지입니다. 언젠가 스토리지 엔진에 트리거를 직접 추가 할 수도 있습니다.

그러나 가난한 트리거 구현과 매우 유용한 외래 키 제약 조건 지원 중에서 어떤 요소를 선택해야하는지에 대한 의견이 있습니다. 데이터베이스 일관성에 익숙해지면 PostgreSQL을 좋아할 것입니다.

12 / 2017-MySQL에 대한이 편집 업데이트 :

의견에 @IstiaqueAhmed가 언급 했듯이이 주제에 대한 상황이 변경되었습니다. 따라서 링크를 따라 가서 실제 상황을 확인하십시오 (나중에 다시 변경 될 수 있음).


8
ON DELETE CASCADE : dangerous-소금 한 덩어리를 섭취하십시오.
언젠가

3
계단식을 조심해야합니다. 많은 레코드를 변경해야 할 경우 시스템을 잠글 수 있습니다. Cascde 삭제는 사용하기 전에 특히주의해서 살펴 봐야합니다. 하위 레코드가있는 경우 삭제가 발생하지 않도록하려는 경우가 종종 있습니다. 고객이 이전에 보유한 오더의 재무 데이터를 삭제하기 위해 고객을 삭제하고 싶지 않습니다. 때로는 계단식 연결이 설정되어 있지 않은지 확인하고 레코드를 비활성 상태로 만드는 방법을 제공하는 것이 좋습니다.
HLGEM

1
비즈니스 로직의 측면에서 흥미로운 일이 될 수있는 하나의 경우가있다 SET NULLON UPDATE회사를 업데이트하는 회사> 사용자 관계의 분리를 나타냅니다. 예 : 회사가 비즈니스 유형을 변경하면 이전 사용자는 더 이상 해당 비즈니스와 관련이 없을 수 있으므로이 NULL인덱스에 적합 할 수 있습니다.
CPHPython

1
@regilero, 당신의 첫 번째 링크 (콘텐츠 보인다 dev.mysql.com/doc/refman/5.6/en/triggers.html MySQL의 사이트가) 변경되었습니다. 그것은 This includes changes to base tables that underlie updatable views당신이 붙여 넣은 대신에 말합니다They do not activate for changes in views
Istiaque Ahmed

6
"고객이 이전 주문의 재무 데이터를 삭제하기 위해 고객을 삭제하고 싶지는 않습니다." 그런 상황에서 어쨌든 여전히 고객의 데이터가 필요할 것입니다. 디자인은 데이터베이스에서 행을 삭제하지 않고 고객을 비활성으로 표시해야합니다. 당신이 실제로 것을 실제로, 나의 전문적인 경험이었다 매우 드물게 삭제하지 않으려는 아무것도 기본적으로 비활성 표시 선호. 영구적으로 삭제는 경우 입니다 확인, CASCADE DELETE일반적으로도 괜찮도 바람직하다. 나는 그것을 특히 위험한 것으로 간주하지 않습니다.
GrandOpener

3

@MarkR 답변에 추가-ORM이있는 많은 PHP 프레임 워크는 고급 DB 설정 (외부 키, 계단식 삭제, 고유 제약 조건)을 인식하거나 사용하지 않으므로 예기치 않은 동작이 발생할 수 있습니다.

예를 들어 ORM을 사용하여 레코드를 DELETE CASCADE삭제하고 관련 테이블에서 레코드를 삭제하면 ORM이 이러한 관련 레코드를 삭제하려고하면 (종종 자동) 오류가 발생합니다.


11
특정 ORM을 사용하지 않는 이유입니다. 데이터베이스 지원이 부족한 도구는 신뢰할 수 없습니다. 외래 키 및 계단식 삭제 또는 업데이트는 고급 개념이 아닌 DB 기본이며 외래 키 제약 조건 없이는 실제 데이터베이스를 설계 할 수 없습니다!
HLGEM

문제는 오류가 발생한다는 것입니다. 삭제를 제한 할 수 있지만 엔진이 오류를 생성하지 않지만 의미를 유지 관리 할 수 ​​있습니까? 다른 데이터가 삭제되지 않도록 보호하면서 프로그램을 계속 진행하고 싶습니다.
TheRealChx101 2016 년

2

응용 프로그램과 관련하여이를 고려해야합니다. 일반적으로 데이터베이스가 아닌 응용 프로그램을 디자인해야합니다 (데이터베이스는 단순히 응용 프로그램의 일부 임).

애플리케이션이 다양한 경우에 어떻게 대응해야하는지 고려하십시오.

기본 동작은 작업을 제한 (허용하지 않음)하는 것입니다. 일반적으로 바보 같은 프로그래밍 오류를 방지하기 위해 원하는 작업입니다. 그러나 DELETE CASCADE에서도 유용 할 수 있습니다. 실제로 응용 프로그램과 특정 객체를 삭제하려는 방법에 따라 다릅니다.

개인적으로 InnoDB는 FK 제약 조건이 있기 때문에 데이터를 휴지통에 버리지 않기 때문에 사용합니다 (참조 MyISAM).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.