[database] 외래 키에 어떤 문제가 있습니까?

Podcast 014 에서 Joel Spolsky 가 외래 키를 거의 사용하지 않았다는 언급을 들었습니다 . 그러나 필자는 데이터베이스 전체에서 중복 및 후속 데이터 무결성 문제를 피하는 것이 매우 중요합니다.

사람들이 이유에 대해 확실한 이유가 있습니까 (스택 오버플로 원칙에 따른 토론을 피하기 위해)?

편집 : “아직 외래 키를 만들 이유가 아직 없기 때문에 이것이 실제로 하나를 설정 한 첫 번째 이유 일 수 있습니다.”



답변

외래 키를 사용하는 이유 :

  • 당신은 고아 행을 얻을 수 없습니다
  • 캐스케이드 삭제시 동작을 자동으로 수행하여 테이블을 자동으로 정리할 수 있습니다.
  • 데이터베이스의 테이블 간 관계를 알면 옵티마이 저가 조인 카디널리티에 대한 더 나은 추정치를 얻을 수 있으므로 쿼리가 가장 효율적인 실행을 위해 쿼리를 계획하는 데 도움이됩니다.
  • FK는 데이터베이스에서 수집해야 할 통계가 가장 중요한 힌트를 제공하여 성능이 향상됩니다.
  • 그들은 모든 종류의 자동 생성 지원을 가능하게합니다 .ORM은 스스로 생성 할 수 있으며 시각화 도구는 멋진 스키마 레이아웃을 만들 수 있습니다.
  • 암묵적 관계가 명시 적으로 문서화되어 있기 때문에 프로젝트를 처음 접하는 사람이 사물 흐름에 더 빨리 도달

외래 키를 사용하지 않는 이유 :

  • FK 일관성을 확인해야하기 때문에 모든 CRUD 작업 에서 DB 작업을 추가로 수행하고 있습니다. 이탈이 많은 경우 큰 비용이 될 수 있습니다.
  • FK는 관계를 적용하여 사물을 추가 / 삭제해야하는 순서를 지정하므로 DB가 원하는 작업을 거부 할 수 있습니다. (이러한 경우, 고아 행을 만드는 것이 일반적이며 좋지 않습니다.) 대규모 배치 업데이트를 수행 할 때 특히 고통스럽고 두 번째 테이블이 일관된 상태를 만드는 상태에서 한 테이블을 다른 테이블보다 먼저로드합니다 (하지만 두 번째로드가 실패하고 데이터베이스가 일치하지 않습니까?).
  • 때로는 데이터가 더러워 질 것이라는 것을 미리 알고, 동의하며, DB가 데이터를 수락하기를 원합니다
  • 당신은 단지 게으르고 있습니다 🙂

나는 대부분의 확립 된 데이터베이스가 적용되지 않고 외래 키를 지정하는 방법을 제공한다고 생각합니다 (확실하지 않습니다!). 비 집행은 FK를 사용하지 않는 모든 이유를 없애기 때문에 두 번째 섹션의 이유 중 하나라도 해당되는 경우 해당 경로를 사용해야합니다.


답변

이것은 육성 문제입니다. 당신의 교육 또는 직업 경력의 어딘가에 데이터베이스를 공급하고 돌보는 데 시간을 보냈거나 (또는 ​​재능있는 사람들과 긴밀히 협력했다면), 실체와 관계의 기본 교리가 당신의 사고 과정에 잘 구속되어 있습니다. 이러한 기초 중 하나는 데이터베이스에 키를 지정하는 방법 / 언제 / 이유 (1 차, 외부 및 대체)입니다. 두 번째 본성입니다.

그러나 RDBMS 관련 노력으로 과거에 철저하거나 긍정적 인 경험을하지 않았다면 그러한 정보에 노출되지 않았을 가능성이 있습니다. 또는 과거에 데이터베이스가 우연히 안티 바이러스 환경 인 환경에 몰입 한 적이있을 수 있습니다 (예 : “DBA는 바보입니다. 적은 시간에 우리는 Java / C # 코드 슬링거가 하루를 절약 할 수있는 적은 몇 가지를 선택했습니다”). 그냥 들으면 FK (그리고 그들이 암시 할 수있는 제약 사항)가 정말 중요하다는 것을 알려주는 일부 dweeb의 비전에 대한 비웃음.

대부분의 사람들은 그들이 어렸을 때 양치질이 중요하다는 것을 배웠다. 당신은 그것없이 얻을 수 있습니까? 물론, 어딘가에 줄을 서서 식사 할 때마다 닦았을 때보 다 치아가 적습니다. 엄마와 아빠가 구강 위생뿐만 아니라 데이터베이스 디자인을 다루는 데 충분한 책임이 있다면 우리는이 대화를하지 않을 것입니다. 🙂


답변

나는 당신이 그것을 벗어날 수있는 많은 응용 프로그램이 있다고 확신하지만 최선의 아이디어는 아닙니다. 데이터베이스를 올바르게 관리하기 위해 항상 응용 프로그램을 사용할 수는 없으며 솔직히 데이터베이스를 관리하는 것이 응용 프로그램에 큰 관심을 가져서는 안됩니다.

관계형 데이터베이스를 사용하는 경우 일부 관계가 정의되어 있어야합니다. 불행히도이 태도 (외래 키가 필요하지 않음)는 데이터 무결성과 같은 바보 같은 것들에 신경 쓰지 않는 많은 응용 프로그램 개발자들이 수용하는 것 같습니다 (그러나 회사에 전용 데이터베이스 개발자가 없기 때문에 필요합니다). 일반적으로 이러한 유형으로 구성된 데이터베이스에서는 기본 키만 있으면 운이 좋습니다.)


답변

외래 키는 모든 관계형 데이터베이스 모델에 필수적 입니다.


답변

항상 사용하지만 금융 시스템 용 데이터베이스를 만듭니다. 데이터베이스는 응용 프로그램의 중요한 부분입니다. 재무 데이터베이스의 데이터가 완전히 정확하지 않은 경우 실제로 코드 / 프런트 엔드 디자인에 얼마나 많은 노력을 기울이고 있는지는 중요하지 않습니다. 당신은 단지 시간을 낭비하고 있습니다.

또한 여러 시스템이 일반적으로 데이터를 읽는 다른 시스템 (Crystal Reports)에서 데이터를 삽입하는 시스템 (내가 디자인 한 API를 사용할 필요는 없음)에 이르기까지 데이터베이스와 직접 인터페이스해야한다는 사실도 있습니다. VBScript를 발견하고 SQL 상자에 대한 SA 암호가있는 둔한 관리자). 데이터베이스가 가능한 한 바보 같은 증거가 아닌 경우에는 데이터베이스를 사용하십시오.

데이터가 중요하다면 외래 키를 사용하고 데이터와 상호 작용하는 저장 프로 시저 모음을 만들고 가능한 가장 어려운 DB를 만드십시오. 데이터가 중요하지 않은 경우 왜 데이터베이스를 시작해야합니까?


답변

업데이트 : 나는 항상 외래 키를 사용합니다. “복잡한 테스트”라는 이의 제기에 대한 나의 대답은 “단위 테스트를 작성하여 데이터베이스가 전혀 필요하지 않습니다. 데이터베이스를 사용하는 모든 테스트는 적절하게 사용해야하며 외래 키도 포함됩니다. 설정이 어려운 경우, 설치하는 데 덜 고통스러운 방법을 찾으십시오. “


외래 키는 자동화 된 테스트를 복잡하게합니다

외래 키를 사용한다고 가정합니다. “금융 계정을 업데이트 할 때 거래 기록을 저장해야합니다”라는 자동 테스트를 작성하고 있습니다. 이 테스트에서는 두 테이블에만 관심이 있습니다 : accountstransactions.

그러나 accounts에 외부 키를 보유 contracts하고, contracts에 FK을 보유 clients하고 clients에 FK을 보유 cities하고 cities에 FK를 갖는다 states.

이제 데이터베이스는 테스트와 관련이없는 4 개의 테이블에 데이터를 설정하지 않고 테스트를 실행할 수 없습니다 .

이에 대한 두 가지 가능한 관점이 있습니다.

  • “이것은 좋은 일이다. 테스트는 현실적이어야하고, 이러한 데이터 제약은 프로덕션에 존재할 것이다.”
  • “이것은 나쁜 일이다. 다른 부분을 포함하지 않고 시스템의 부분을 테스트 할 수 있어야한다. 시스템에 대한 통합 테스트를 전체적으로 추가 할 수있다.”

테스트를 실행하는 동안 외래 키 검사를 일시적으로 해제 할 수도 있습니다. 적어도 MySQL 은 이것을 지원합니다 .


답변

“레코드를 삭제하는 것이 더 번거로울 수 있습니다. 다른 테이블에 외래 키가 해당 제약 조건을 위반하는 레코드가있는”마스터 “레코드는 삭제할 수 없습니다.”

SQL 표준은 외래 키가 삭제되거나 업데이트 될 때 수행되는 동작을 정의한다는 점을 기억해야합니다. 내가 아는 것은 :

  • ON DELETE RESTRICT-이 열에 키가있는 다른 테이블의 행이 삭제되지 않도록합니다. 이것이 Ken Ray가 위에서 설명한 것입니다.
  • ON DELETE CASCADE -다른 테이블의 행이 삭제되면이 테이블에서이를 참조하는 행을 삭제하십시오.
  • ON DELETE SET DEFAULT -다른 테이블의 행이 삭제되면이를 참조하는 외래 키를 열의 기본값으로 설정하십시오.
  • ON DELETE SET NULL -다른 테이블의 행이 삭제되면이 테이블에서이를 참조하는 외래 키를 null로 설정하십시오.
  • ON DELETE NO ACTION-이 외래 키는 외래 키임을 나타냅니다. 즉 OR 매퍼에 사용됩니다.

동일한 작업이에 적용됩니다 ON UPDATE.

기본값은 사용중인 서버.