답변:
데이터베이스에 외래 키를 넣습니다. 저장하기 전에 응용 프로그램에서 데이터의 유효성을 검사하더라도 FK는 좋은 QA 백업입니다. 첫 번째 근사치의 경우 응용 프로그램에는 항상 데이터 문제가 있습니다. 이와 같은 컨트롤을 시스템 외부에두면 데이터가 자동으로 손상되는 오류 모드 만 초대됩니다.
몇 년 동안 데이터웨어 하우징에서이 작업을 수행하는 것만 큼 좋은 것은 없습니다. 응용 프로그램 코드에서 데이터 무결성을 강화할 수 있다고 생각한 응용 프로그램 개발자가 실수를 저지른 후 조각을 집는 데 시간을 보냅니다. 이 작업을 수행 할 때마다 시간을 투자하면 응용 프로그램 관리 데이터 무결성이 단순한 문제 일 뿐이라는 결론을 내릴 수 있습니다.
또한 쿼리 옵티마이 저는 외래 키를 사용하여 테이블 조인에 대한 정보를 유추 할 수 있으므로 FK는보다 효율적인 쿼리 계획을 제공합니다.
외래 키에도 많은 다른 이점이 있습니다. FK를 데이터베이스에 올려 놓으십시오.
DBA에 초점을 맞춘 그룹이기 때문에 여기서는 투표가 중단 될 것으로 예상됩니다.
대부분의 시나리오에서 엄격한 외래 키를 사용하는 것이 최선의 결정이라는 데 동의합니다. 그러나 외래 키가 해결하는 것보다 더 많은 문제를 일으키는 경우가 있습니다.
트래픽이 많은 웹 응용 프로그램과 같이 매우 동시성이 높은 환경을 처리하고 잘 확립 된 강력한 ORM을 사용하는 경우 외래 키로 인해 잠금 문제가 발생하여 서버 확장 및 유지 관리가 어려워 질 수 있습니다. 자식 테이블에서 행을 업데이트 할 때 부모 행도 잠 깁니다. 많은 시나리오에서 경쟁 경합으로 인해 동시성이 크게 제한 될 수 있습니다. 또한 때로는 의도적으로 참조 무결성 규칙을 일시적으로 위반해야하는 보관 프로세스와 같은 개별 테이블에 대해 유지 관리를 수행해야합니다. 외래 키를 사용하면이 작업을 수행하기가 매우 어려울 수 있으며 일부 RDBMS에서 외래 키 제약 조건을 사용하지 않도록 설정하면 상당한 시간이 걸리는 시간이 많이 걸리는 프로세스 인 테이블을 다시 작성하게됩니다.
데이터베이스 외부의 참조 무결성을 이해할 수있는 강력한 프레임 워크를 사용해야한다는 경고를 포함하고 있음을 이해합니다. 그래도 참조 무결성 문제가 발생할 수 있습니다. 그러나 고아 행이나 사소한 참조 무결성 위반이 그다지 중요하지 않은 경우가 많습니다. 웹 응용 프로그램의 대부분이이 범주에 속한다고 주장합니다.
즉, 아무도 페이스 북으로 시작하지 않습니다. 데이터베이스에서 외래 키를 정의하여 시작하십시오. 감시 장치. 문제가 발생하면 이러한 제약 조건 중 일부를 조정하여 삭제해야 할 수도 있습니다.
결론 : 대부분의 데이터베이스에는 외래 키가 있어야합니다. 외래 키가 없으면 높은 동시 환경이 더 나을 수 있습니다. 해당 지점에 도달하면 해당 제약 조건을 삭제하는 것이 좋습니다.
난 지금 난연제를 입을거야.
편집 2012-03-23 7:00 AM
외래 키의 잠금 결과에 대해 생각하면서 내부적으로 내부적으로 생성되어 서버로드에 추가되는 모든 추가 행 조회 비용을 언급하지 않았습니다.
궁극적으로, 내 요점은 외래 키가 자유롭지 않다는 것입니다. 많은 경우에, 그 가치는 가치가 있지만, 그 비용이 그들의 이익을 초과하는 시나리오가 있습니다.
편집 2012-03-23 7:38 AM
구체적으로합시다. 이 예제에서 외래 키 동작을 높이 평가하지는 않지만 MySQL / InnoDB를 선택하고 있지만 가장 친숙하고 가장 일반적으로 사용되는 웹 데이터베이스 일 것입니다. 내가 보여줄 예제와 함께 다른 데이터베이스가 더 나을 것이라고 확신하지는 않습니다.
부모를 참조하는 외래 키가있는 자식 테이블을 고려하십시오. 예를 들어, MySQL의 sakila 샘플 데이터베이스에서 film 및 film_actor 테이블을 참조하십시오.
CREATE TABLE `film` (
`film_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`description` text,
`release_year` year(4) DEFAULT NULL,
`language_id` tinyint(3) unsigned NOT NULL,
`original_language_id` tinyint(3) unsigned DEFAULT NULL,
`rental_duration` tinyint(3) unsigned NOT NULL DEFAULT '3',
`rental_rate` decimal(4,2) NOT NULL DEFAULT '4.99',
`length` smallint(5) unsigned DEFAULT NULL,
`replacement_cost` decimal(5,2) NOT NULL DEFAULT '19.99',
`rating` enum('G','PG','PG-13','R','NC-17') DEFAULT 'G',
`special_features` set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') DEFAULT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`film_id`),
KEY `idx_title` (`title`),
KEY `idx_fk_language_id` (`language_id`),
KEY `idx_fk_original_language_id` (`original_language_id`),
CONSTRAINT `fk_film_language` FOREIGN KEY (`language_id`) REFERENCES `language` (`language_id`) ON UPDATE CASCADE,
CONSTRAINT `fk_film_language_original` FOREIGN KEY (`original_language_id`) REFERENCES `language` (`language_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8
CREATE TABLE `film_actor` (
`actor_id` smallint(5) unsigned NOT NULL,
`film_id` smallint(5) unsigned NOT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`actor_id`,`film_id`),
KEY `idx_fk_film_id` (`film_id`),
CONSTRAINT `fk_film_actor_actor` FOREIGN KEY (`actor_id`) REFERENCES `actor` (`actor_id`) ON UPDATE CASCADE,
CONSTRAINT `fk_film_actor_film` FOREIGN KEY (`film_id`) REFERENCES `film` (`film_id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
관련 제약 조건은 내 예에서 film_actor (fk_film_actor_film)입니다.
session1> BEGIN;
session1> INSERT INTO film_actor (actor_id, film_id) VALUES (156, 508);
Query OK, 1 row affected (0.00 sec)
session2> BEGIN;
session2> UPDATE film SET release_year = 2005 WHERE film_id = 508;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
자식 테이블에 삽입하는 동안 부모 행에서 관련되지 않은 필드를 업데이트 할 수 없습니다. InnoDB가 film_actor의 FK 제약으로 인해 film.film_id = 508 인 행에 공유 잠금을 보유하고 있기 때문에 해당 행에 대한 UPDATE는 필요한 독점 잠금을 얻을 수 없기 때문에 발생합니다. 해당 작업을 취소하고 UPDATE를 먼저 실행하면 동일한 동작이 발생하지만 INSERT는 차단됩니다.
session1> BEGIN;
session1> UPDATE film SET release_year = 2005 WHERE film_id = 508;
Query OK, 1 row affected (0.00 sec)
session2> BEGIN;
session2> INSERT INTO film_actor (actor_id, film_id) VALUES (156, 508);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
users
웹 애플리케이션에서 종종 수십 개의 관련 테이블이 있는 테이블을 고려하십시오 . 본질적으로 모든 관련 행에 대한 조작은 상위 행에 대한 갱신을 방지합니다. 외래 키 관계가 여러 개이고 동시성이 많은 경우에는 문제가 될 수 있습니다.
FK 제약 조건으로 인해 테이블 유지 관리에 대한 해결 방법도 까다로울 수 있습니다. : Percona 피터 Zaitsev 더 나은 내가 할 수있는 것보다 그것을 설명하고 이에 대한 블로그 게시물이 하이재킹 이노 디비 외래 키를 .