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


259

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

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

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


9
나는 Joel이 FK를 사용하지 않는다고 생각하지 않습니다. 단지 그가 데이터베이스를 강제로 실행시키지 않는 것입니다. 논리적으로, 그들은 여전히 ​​FK입니다!
대런 토마스

6
그는 외래 키를 사용하지 않는다고 말하지만 대런은 외래 키를 사용하지 않는다는 데 동의합니다. 제약 조건 추가 여부에 관계없이 다른 테이블의 기본 / 고유 키에서 값을 가져 오는 테이블의 열은 외래 키입니다.
Tony Andrews

22
... 일반적으로 제약 조건을 추가하지 않는 것은 어리석은 일입니다. 응용 프로그램 코드에 버그가 있거나 데이터 "수정"을 수행하는 장면 뒤에서 작업하는 경우에도 항상 무결성을 유지합니다.
Tony Andrews

2
+1 Tony의 의견입니다. 기능과 외래 키의 논리적 개념 사이에는 너무 많은 혼란이 있습니다.
JohnFx

4
@ DanMan, 당신이 생각하는 인상을 어디서 얻었는지 모르겠다. 나는 실제로 위에서 언급했다. "일반적으로 제약 조건을 추가하지 않는 것은 어리석은 일이다. 그것은 항상 무결성을 유지한다"
Tony Andrews

답변:


352

외래 키를 사용하는 이유 :

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

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

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

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


12
좋은 목록! DBM은 CRUD의 "R"부분에 대한 일관성을 검사하지 않으므로 그 부분을 제거하겠습니다. 또한 앱에서 DBMS와 동일한 작업을 수행하기 때문에 아마도 세척 일 것입니다 .CRD 전에 부모 ID가 유효한지 확인하고 실제로 DBM이 수행하는 것보다 느린 지 확인하십시오!
매트 Rogish

6
자녀를 삽입하는 동안 누군가 부모를 삭제하면 어떻게 되나요? 지금 "댓글 추가"를 제출할 때-이미 답변을 삭제 한 경우이 메모는 이제 고아입니다. FK는 그것을 막았을 것입니다. 또한 parentID를 원하는 것으로 변경할 수 있습니다. 누군가 확인해야합니다. :)
Matt Rogish

7
정확하게-여러 동시 클라이언트에 직면 한 트랜잭션을 보장 할 수있는 유일한 데이터베이스이기 때문에 DB 작업이되어야합니다.
SquareCog

3
+1 탁월한 답변-FK 제약 조건을 사용하지 않는 두 번째 이유는 실제로 일관성이 좋은 "일관성을 깨뜨리기가 더 어려워집니다"라고 생각할 수 있습니다 !
Bill Karwin

9
외래 키 사용의 이점 FAR은 내 의견으로는 외래 키를 사용하지 않을 때의 이점보다 중요합니다.
Nick Bedford

80

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

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

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


61
나는 증류수를 사용할 것입니다. "외래 키는 양치질과 같습니다. 계속하고,하지 않고주의를 기울여야합니다."
Mark Sowul

5
저는 개인적으로 RDBMS의 원리가 구강 위생의 원리보다 훨씬 단순하고 잘 정의되어 있음을
알고 있습니다

10 년 후, 나는이 데이터베이스 디자인이 내 아들 / 딸과 대화하도록함으로써 데이터베이스 문제로 인해 다음 월스트리트 충돌의 원인이 될 수 있습니다.
VarunAgw

52

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

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


26
나는 데이터베이스에 FK가없는 사람들을 실제로 얻지 못합니다. 내가 그것을 가지고 있지 않은 사람과 마지막으로 일할 때, 그는 "아니요, 우리는 그것을 응용 프로그램에서 시행합니다." 제가 모든 고객 데이터베이스를 조사한 후 대부분의 고객 데이터베이스에 고아가 있다는 것을 제외하고는 ...
ErikE

1
보통 그런 것 같습니다. 나는 사용자가 런타임 예외를 신경 쓰지 않는 한 데이터베이스에서만 적용 할 수 있다고 생각하지만 둘 다 갖는 유일한 방법입니다.
AlexCuse

"Atwood : ... 당신이 색인에 설정 한 외래 키를 기반으로, 그들은 그것을 알아냅니다 ... Spolsky : [웃음] 당신이 그렇게한다고 가정합니다. 데이터베이스를 올바르게 설정했습니다 ... "
MemeDeveloper

4
데이터베이스가 호출되지 않은 관계 때문에의 관계 테이블 사이 (데이터베이스의 모든 종류의 엔티티 사이의 관계의 어떤 종류가 있어요!)하지만, 테이블 때문에 자신은 관계 수학 용어는. Wikipedia를 참조하십시오 .
Massimiliano Kraus

41

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


54
모델입니다. 필수는 아니지만 구현이 유용 할 것입니다.
dkretz 2016 년

4
죄송하지만 앱 개발자가 객체 데이터베이스 관리 시스템 (일명 NoSQL 데이터베이스)을 더 널리 사용하지 않는 주된 이유는 RDBMS에 대한 투자 때문입니다. 대부분의 데이터베이스 (데이터베이스 관리 시스템이 아님)는 종종 분산 캐시를 포함하는 중간 계층 개체 모델입니다. 여기서는 삭제 캐스 케이 딩, 소유권 및 변경 사항 동기화가 발생해야합니다. RDBMS는 주로이 오브젝트 모델의 지속성을 위해 사용되며 일반적으로 힘들고 실질적으로 가치없는 ORM 운동 후에 사용됩니다. 관계 모델은 대부분 필요하지 않습니다!
Sentinel

2
아니오, 외래 키는 "관계형"을 나타 내기 위해 의무적으로 요구되지 않습니다
Silver Moon

이것은 실제로 많은 설명을하지 않습니다.
Nae

29

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

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

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


2
좋은 통찰력. 실제로 사용되는 모든 응용 프로그램에서 데이터가 중요하다고 주장합니다. 유일한 차이점은 손상된 데이터의 결과입니다. 그들은 ... 응용 프로그램의 당신의 친절에 대한 높은
제이 드세

20

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


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

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

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

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

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

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

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


FK를 사용하고 다양한 테스트 시나리오를 지원하도록 DB를 설정하는 단위 테스트 도우미 메서드를 작성합니다. 예를 들어 테스트에 대해 "도시"및 "상태"를 채우는 도우미 메서드 해당 테이블을 채워야합니다.
joelpt

관련이없는 엔터티간에 링크 테이블을 사용해야합니다. 더 나아가서 별도의 DBS : 각 요소 (클라이언트, 계정, 트랜잭션)가 서로 다른 DB를 가진 서로 다른 시스템 인 서비스 지향 아키텍처 또는 마이크로 서비스의 상황을 고려하십시오. 그들 사이에는 FK가 없습니다. 이 경우 각 유형의 데이터에 대해 서브 테이블에서 분리 된 데이터를 방지하기 위해 FK를 사용해야합니다.
JeeBee

3
제약에 허용 DBMS도있다 지연 이 전체 트랜잭션을 커밋 할 때 그들은 단지 삽입, 업데이트의 순서 때문에, 확인되도록, 삭제는 중요하지 않습니다
a_horse_with_no_name

2
비즈니스 계층에서 업데이트를 테스트하는 경우 개발 환경에 FK가 있어야합니다. 레코드를 업데이트 할 때 업데이트에 필요한 열 값이 있어야합니다. 그렇지 않으면 IMHO 테스트가 유효하지 않습니다.
KeyOfJ

3
데이터베이스는 단위 테스트에 관여해서는 안되며 모의해야합니다. 통합 테스트에서는 관련 테스트가 수행되지만 외래 키로 인한 문제는 수정하지 않는 한 사용자가 겪게되는 문제입니다.
Andreas Bergström

16

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

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.

기본값은 사용중인 서버.


14

@ imphasing-이것은 유지 보수의 악몽을 일으키는 사고의 종류입니다.

왜 오, 왜 "약간의 예방책"인 소위 "소프트웨어 시행"을 위해 데이터가 최소한 일관성을 보장 할 수있는 선언적 참조 무결성을 무시하겠습니까 ?


관련 개발자가 사소하고 정규화 된 관계형 모델을 요구하는 문제를 해결 한 적이 없기 때문입니다. 많은 문제, 특히 오늘날의 열풍 인 웹 / 소셜 미디어 유형 프로그래밍에 풍부한 종류는 없습니다. ORM 프레임 워크의 백엔드에서 드리블 된 것이 알파의 문제를 만족시키는 경우, 데이터 모델링에 대해 더 많이 생각할 가능성은 거의 없습니다. 이러한 많은 문제는 K / V 저장소, 문서 데이터베이스 또는 직선 객체 직렬화로 쉽게 처리 할 수 ​​있습니다.
zxq9

12

사용하지 않는 한 가지 좋은 이유가 있습니다. 자신의 역할을 이해하지 못하거나 사용하는 방법.

잘못된 상황에서 외래 키 제약 조건으로 인해 사고의 폭포 복제가 발생할 수 있습니다. 누군가 잘못된 레코드를 제거하면 실행 취소하면 맘모스 작업이 될 수 있습니다.

반대로, 무언가를 제거해야 할 때, 제대로 설계되지 않은 경우 제약 조건으로 인해 모든 종류의 잠금이 발생하여 방해 할 수 있습니다.


8
백업없이 프로덕션에서 행을 삭제하는 것은 유효한 인수가 아닙니다. 이해하지 못하면 생략하지 말고 배우는 것이 좋습니다.
기 illa

2
@Guillaume 나는 그의 대답이 약간 냉소적이라고 생각합니다. 문자 그대로 받아들이지 말아야합니다. 그러나 물론 당신이 해야 모두 이해하고 사용합니다.
Benjamin

^ 이것. 그것들은 유용한 도구이지만 초보자의 손에는 위험한 도구입니다.
Kent Fredric

11

고아 행이 큰 문제가 아닌 한, 사용 하지 않는 좋은 이유 는 없습니다.


11
고아 행이 중요한 이유는 무엇입니까?
Seun Osewa

2
멀티 스레딩은 어떻습니까? 특정 상황에서 멀티 스레딩 악몽을 일으킬 수 있습니다. 서로를 참조해야하는 객체가 발생할 수있는 데이터베이스를 작성하는 다중 스레드가있는 복잡한 응용 프로그램에서는 비즈니스 로직에서 참조 무결성을 제어하는 ​​것이 좋습니다. 특히 테이블이 나중에 정적 상태가되는 경우에 더욱 좋습니다.
Keith Pinson

나는 동의한다. 또한, 나는 무자비하게 버리는 것보다 나중에 복구 할 수있는 ophan 행을 선호합니다.
PedroD

4

더 큰 질문은 : 눈가리개로 운전하겠습니까? 참조 제한이없는 시스템을 개발하는 것이 바로 그 방법입니다. 비즈니스 요구 사항 변경, 응용 프로그램 디자인 변경, 코드 변경에 대한 각각의 논리적 가정, 논리 자체가 리팩터링 될 수 있습니다. 일반적으로 데이터베이스의 제약 조건은 현대 논리적 가정하에 배치되며 특정 논리적 주장 및 가정에 대해 올바른 것으로 보입니다.

응용 프로그램의 수명주기를 통해 참조 및 데이터 검사는 특히 새로운 요구 사항으로 인해 논리적 응용 프로그램 변경이 발생하는 경우 응용 프로그램을 통해 경찰 데이터 수집을 제한합니다.

이 리스팅의 주제에 따르면 , 외래 키는 그 자체로 "성능을 향상"시키거나 실시간 트랜잭션 처리 시스템의 관점에서 성능을 크게 저하시키지 않습니다. 그러나 대용량 "배치"시스템에서는 제약 조건 검사에 대한 총 비용이 있습니다. 여기에 실시간과 배치 트랜잭션 프로세스의 차이점이 있습니다. 배치 처리-제약 조건 검사에 의해 발생 된 순차적으로 처리 된 배치의 막대한 비용으로 인해 성능이 저하되는 경우.

잘 설계된 시스템에서, 데이터 일관성 검사는 일괄 처리를 "이전에"수행 할 수 있습니다 (그럼에도 불구하고 여기에도 관련 비용이 있습니다). 따라서로드 시간 동안 외래 키 제약 조건 검사가 필요하지 않습니다. 실제로 배치가 처리 될 때까지 외래 키를 포함한 모든 제약 조건을 일시적으로 비활성화해야합니다.

QUERY PERFORMANCE- 테이블이 외래 키에서 조인 된 경우 외래 키 열이 INDEXED가 아님을 인식해야합니다 (각 기본 키는 정의에 의해 색인화 됨). 이 문제를 위해 외래 키를 색인화하면 키를 색인화하고 색인에서 테이블을 조인하면 색인화되지 않은 키를 외래 키 제약 조건으로 조인하는 것이 아니라 성능을 향상시킬 수 있습니다.

데이터베이스가 웹 사이트 표시 / 렌더링 콘텐츠 등을 지원하고 클릭을 기록하는 경우 주제 변경 , 모든 테이블에 대한 전체 제약 조건이있는 데이터베이스는 그러한 목적으로 종료됩니다. 생각 해봐 대부분의 웹 사이트는 데이터베이스를 사용하지 않습니다. 데이터가 방금 기록되고 언급되지 않은 유사한 요구 사항에 대해서는 제약이없는 인 메모리 데이터베이스를 사용하십시오. 이것은 데이터 모델이없고 논리 모델이 있지만 물리적 데이터 모델이 없다는 것을 의미하지는 않습니다.


글쎄, 왜 공백 대신에 두 개의 줄 바꿈을 삽입하고 두 단어를 '67 %가 Jonathan Leffler '로 바꾸는 지 모르겠지만 그와 같은 일을 많이하지 않았다고 생각합니다. 본문은 @jay (사용자 183837)가 작성했습니다.
Jonathan Leffler

나는 대부분의 다른 사이트에서와 같이 여기에서 paragrahps가 작동하지 않는다고 가정했습니다. 그래서 흐름 변경을 위해 굵은 글씨를 사용하여 모두 하나로했습니다.
jasbir L

3

외래 키를 사용하는 추가 이유 :-데이터베이스를 더 많이 재사용 할 수 있습니다.

외래 키를 사용하지 않는 추가 이유 :-재사용을 줄임으로써 고객을 도구에 고정 시키려고합니다.


3

내 경험상 데이터베이스 크리티컬 애플리케이션에서 FK를 사용하지 않는 것이 좋습니다. 나는 FK가 좋은 습관이지만 데이터베이스가 크고 CRUD 작업 / 초가 큰 곳에서는 실용적이지 않다고 말하는 사람들에 동의하지 않을 것입니다. 이름 없이도 공유 할 수 있습니다. 가장 큰 투자 은행 중 하나는 데이터베이스에 단일 FK가 없습니다. 이러한 제약은 프로그래머가 처리하며 DB와 관련된 응용 프로그램을 만듭니다. 기본적인 이유는 새로운 CRUD가 완료 될 때마다 여러 테이블에 영향을 미치고 각 삽입 / 업데이트에 대해 확인해야하지만 단일 행에 영향을주는 쿼리에는 큰 문제는 아니지만 처리 할 때 큰 대기 시간이 발생하기 때문입니다. 모든 대형 은행이 일상적인 작업으로 수행해야하는 일괄 처리.

FK를 피하는 것이 좋지만 프로그래머가 위험을 처리해야합니다.


8
나는 큰 은행의 개발 관행이 황금 표준을 설정한다고 생각하지 않습니다.
Adriaan Koster

3

"레코드를 추가하기 전에 해당 레코드가 다른 테이블에 있는지 확인하십시오"는 비즈니스 논리입니다.

데이터베이스에서 이것을 원하지 않는 몇 가지 이유는 다음과 같습니다.

  1. 비즈니스 규칙이 변경되면 데이터베이스를 변경해야합니다. 데이터베이스는 많은 경우 인덱스를 다시 작성해야하며 이는 큰 테이블에서 느립니다. 변경 규칙에는 손님이 댓글을 올리더라도 메시지를 게시하거나 사용자가 자신의 계정을 삭제할 수 있도록하는 등이 포함됩니다.

  2. 데이터베이스를 변경하는 것은 변경 사항을 프로덕션 저장소로 푸시하여 소프트웨어 수정 사항을 배치하는 것만 큼 쉽지 않습니다. 데이터베이스 구조를 가능한 많이 변경하지 않기를 원합니다. 데이터베이스에 비즈니스 로직이 많을수록 데이터를 변경하고 다시 인덱싱을 트리거해야 할 가능성이 높아집니다.

  3. TDD. 단위 테스트에서는 모의 데이터베이스를 대체하고 기능을 테스트 할 수 있습니다. 데이터베이스에 비즈니스 로직이있는 경우 완전한 테스트를 수행하지 않고 테스트 목적으로 데이터베이스를 테스트하거나 코드에서 비즈니스 로직을 복제하여 로직을 복제하고 로직이 작동하지 않을 가능성을 증가시켜야합니다. 같은 길.

  4. 다른 데이터 소스로 논리 재사용 데이터베이스에 논리가 없으면 내 응용 프로그램은 데이터베이스의 레코드에서 개체를 만들고 웹 서비스, json 파일 또는 다른 소스에서 개체를 만들 수 있습니다. 데이터 매퍼 구현을 교체해야하며 모든 비즈니스 로직을 모든 소스와 함께 사용할 수 있습니다. 데이터베이스에 논리가있는 경우 이것이 불가능하며 데이터 매퍼 계층 또는 비즈니스 논리에서 논리를 구현해야합니다. 어느 쪽이든 코드에 해당 검사가 필요합니다. 데이터베이스에 논리가 없으면 다른 데이터베이스 또는 플랫 파일 구현을 사용하여 다른 위치에 응용 프로그램을 배포 할 수 있습니다.


2

이전 답변에 데이터 일관성을 유지하는 데 유용하다는 점에 동의합니다. 그러나 몇 주 전 Jeff Atwood 가 표준화되고 일관된 데이터의 장단점을 논의한 흥미로운 게시물 이있었습니다 .

간단히 말해, 대량의 데이터를 처리 할 때 비정규 화 된 데이터베이스가 더 빠를 수 있습니다. 응용 프로그램에 따라 정확한 일관성에 신경 쓰지 않아도되지만 DB와는 달리 데이터를 처리 할 때 훨씬 더 조심해야합니다.


Jeff는 좋은 지적을합니다. 그러나 "Enterprise Rails"의 Dan Chak은 기본적으로 비정규 화 된 데이터 사본 인 캐시 테이블을 설계하는 방법을 보여줍니다. 쿼리가 빠르게 실행되고 테이블을 새로 고칠 필요가 없으면 제대로 작동합니다. 데이터가 응용 프로그램의 동작 (예 : 응용 프로그램 상태)을 유발하는 경우 데이터가 최대한 표준화되어야합니다.
Jay Godse 2016 년

일관되고 예상되는 액세스 경로에서 대량의 데이터 읽을 때 비정규 화 된 데이터 웨어 하우스 를 사용할 수 있습니다 . 다른 모든 시나리오에서 이것은 위험한 오류입니다.
Peter Wone

2

Clarify 데이터베이스는 기본 또는 외래 키가없는 상용 데이터베이스의 예입니다.

http://www.geekinterview.com/question_details/18869

재미있는 점은 기술 문서가 테이블이 어떻게 관련되어 있는지, 테이블을 조인하는 데 사용할 열 등을 설명하기 위해 많은 시간을 소비한다는 것입니다.

즉, 명시 적 선언 (DRI)을 사용하여 테이블에 조인 할 있지만하지 않기로 선택했습니다 .

결과적으로 Clarify 데이터베이스는 불일치로 가득 차서 성능이 저하됩니다.

그러나 개발자 작업을 더 쉽게 만들고 삭제, 추가하기 전에 관련 행을 확인하는 것과 같은 참조 무결성을 처리하기 위해 코드를 작성할 필요가 없다고 생각합니다.

그리고 그것은 관계형 데이터베이스에 외래 키 제약 조건이 없다는 주요 이점입니다. 그것은 적어도 악마를 돌볼 수있는 관점에서 개발하는 것이 더 쉬워집니다.


실패한 참조 무결성 검사를 처리하는 코드는 일치하지 않는 데이터를 처리하는 코드보다 훨씬 작습니다.
Jay Godse 2016 년

@ 제이 동의합니다! 내가이 접근법을지지한다고 생각하지 마십시오.
Ed Guiness 2016 년

2

Oracle 데이터베이스 만 알고 있으며 다른 데이터베이스는 없으며 외래 키가 데이터 무결성을 유지하는 데 필수적이라고 말할 수 있습니다. 데이터를 삽입하기 전에 데이터 구조를 작성하고 수정해야합니다. 이것이 완료되면 모든 기본 및 외래 키가 생성되고 작업이 완료됩니다!

의미 : 고아 행? 아니, 내 인생에서 본 적이 없어 나쁜 프로그래머가 외래 키를 잊어 버렸거나 다른 수준에서 외래 키를 구현하지 않은 경우. 둘 다 Oracle과 관련하여 큰 실수로 인해 데이터 복제, 고아 데이터 및 데이터 손상이 발생할 수 있습니다. FK가 적용되지 않은 데이터베이스는 상상할 수 없습니다. 나에게 혼란스러워 보인다. 유닉스 권한 시스템과 비슷합니다. 모두가 루트라고 상상해보십시오. 혼돈을 생각하십시오.

외래 키는 기본 키와 마찬가지로 필수적입니다. 기본 키를 제거하면 어떻게 되나요? 글쎄, 총 혼란이 일어날 것입니다. 그게 다야. 기본 또는 외래 키 책임을 프로그래밍 수준으로 이동할 수 없으며 데이터 수준이어야합니다.

단점? 네 그럼요 ! 삽입시 더 많은 검사가 수행 될 것입니다. 그러나 데이터 무결성이 성능보다 더 중요하다면 당연한 일입니다. Oracle의 성능 문제는 PK 및 FK와 함께 제공되는 인덱스와 관련이 있습니다.


1

레코드 삭제가 더 번거로워 질 수 있습니다. 외래 키가 해당 제한 조건을 위반하는 다른 테이블의 레코드가있는 "마스터"레코드는 삭제할 수 없습니다. 트리거를 사용하여 계단식 삭제를 수행 할 수 있습니다.

기본 키를 현명하게 선택하지 않으면 해당 값을 변경하는 것이 훨씬 더 복잡해집니다. 예를 들어, "고객"테이블의 PK를 사람의 이름으로 사용하고 "주문"테이블에서 해당 키를 FK로 만드는 경우 고객이 자신의 이름을 변경하려면 왕관이됩니다 .. 그러나 그것은 단지 데이터베이스 설계의 문제 일뿐입니다.

Fireign 키를 사용할 때의 이점이 예상되는 단점보다 크다고 생각합니다.


5
어쨌든 물건을 거의 삭제하지 않는 경향이 있습니다. 마크에 "Visible / active"비트가 있습니다.
Dana

+1 "화재 키 사용의 장점이 예상되는 단점보다 크다"
Ian Boyd

2
기본 키의 값을 절대로 변경 하지 마십시오 . 당신은 삭제 전체 행을하고 다시 그것을 다르게. 변경 해야한다고 생각하면 스키마에 결함이있는 것입니다.
DanMan

외래 키가 CustomerId (PK)에 설정된 경우 고객 이름을 변경해도 전혀 문제가되지 않습니다. 주문 테이블에. 그것이 고통스러운 유일한 방법은 FK가 CustomerName에 설정되어있는 경우입니다. IMHO
KeyOfJ

1

외래 키 제약 조건을 확인하려면 CPU 시간이 걸리므로 일부 사람들은 외래 키를 생략하여 추가 성능을 얻습니다.


6
중복되고 일관되지 않은 데이터를 제거하는 데 얼마나 많은 CPU 시간이 소비됩니까?
Ed Guiness

그래, 사실이야 내가 작업하는 시스템에서 한 번에 10-40 기가의 데이터를 데이터베이스에 삽입해야하며 총 시간에 관계없이 FK 성능을 볼 수 있습니다.
Paul Mendoza

1

외래 키에 인덱스를 넣는 것을 잊어 버린 특정 조작이 느리다고 불평하는 사람들 로부터이 주장도 들었습니다 (제약 조건 검사는 모든 인덱스를 활용할 수 있기 때문에). 요약하자면 외래 키를 사용하지 않는 좋은 이유는 없습니다. 모든 최신 데이터베이스는 계단식 삭제를 지원하므로 ...


9
FK 제약 조건이 일부 (대부분 제 관점에서) 사용되지 않는 실제 이유는 성능 저축 주장으로 게으름을 방어 할 수 있다고 주장하는 게으른 게으름입니다. 우리 회사가 겪는 어리 석음 비용의 대부분은 FK 제약 조건의 시행 부족과 회사를 통한 파급 효과 때문이라고 확신합니다. 고유 키 부족은 12 단계의 중첩 된 IF 및 임의 들여 쓰기를 사용하여 2000 개 이상의 라인 저장 프로 시저 옆에서 견딜 수있는 또 다른 요소입니다. 그러나 이제 그만하겠습니다.
Chad

1

내가 들었던 주장은 프런트 엔드에 이러한 비즈니스 규칙이 있어야한다는 것입니다. 외래 키는 처음부터 제약 조건을 위반하는 삽입을 허용하지 않아야 할 때 "불필요한 오버 헤드를 추가"합니다. 이것에 동의합니까? 아뇨,하지만 제가 항상 들었습니다.

편집 : 내 생각에 그는 외래 키가 아닌 외래 키 제약 조건을 개념 으로 언급하고 있습니다.


아니. 그는 실제 키를 좋아하지 않습니다!
ljs

저를 놀라게합니다. 외래 키 제약 조건을 좋아하지 않는 것과 외래 키를 좋아하지 않는 것에는 큰 차이가 있습니다. 관계형 데이터베이스가 없는지 잘 모르겠습니다.
lordscarlet

예, 들었을 때 충격을 받았습니다. 그러나 그는 의도 치 않게 혀를 tongue 았을 수도있다. 아마 그는 여기에 게시하고 어떤 단계에서 명확히 할 것입니다 :-)
ljs

1

나에게 ACID 표준을 따르고 싶다면 참조 무결성을 보장하기 위해 외래 키를 갖는 것이 중요합니다.


1

나는 대부분의 의견을 여기에 두어야합니다. 외래 키는 데이터가 무결성을 유지하는 데 필요한 항목입니다. ON DELETE 및 ON UPDATE에 대한 다양한 옵션을 사용하면 사람들이 사용과 관련하여 여기에서 언급 한 "다운 폴트"를 해결할 수 있습니다.

나는 모든 프로젝트의 99 %에서 FK가 데이터의 무결성을 강화해야한다는 것을 알지만, 나쁜 데이터에 관계없이 오래된 데이터를 유지 해야하는 클라이언트가있는 드문 경우가 있습니다 .... 그러나 어쨌든 유효한 데이터 만 가져 오는 코드를 작성하는 데 많은 시간을 소비하므로 의미가 없습니다.


1

애플리케이션 수명주기 전반에 걸쳐 유지 관리 성과 불변성은 어떻습니까? 대부분의 데이터는 데이터를 사용하는 응용 프로그램보다 수명이 더 깁니다. 관계 및 데이터 무결성은 다음 개발 팀이 앱 코드에서 바로 얻을 수 있기를 바랍니다. 자연스런 관계를 존중하지 않는 더티 데이터로 DB를 작업하지 않았다면 그렇게 할 것입니다. 그러면 데이터 무결성의 중요성이 매우 분명해질 것입니다.


1

또한 대부분의 데이터베이스에서 외래 키가 필요하다고 생각합니다. 유일한 일관성 (일관성 강화로 인한 성능 저하 이외에) 외래 키를 사용하면 사람들이 기능 외래 키가 있다고 가정하는 코드를 작성할 수 있다는 것입니다. 절대 허용해서는 안됩니다.

예를 들어, 사람들이 참조 테이블에 삽입 한 다음 첫 번째 삽입이 성공했는지 확인하지 않고 참조 테이블에 삽입을 시도하는 코드를 작성하는 것을 보았습니다. 외래 키를 나중에 제거하면 데이터베이스가 일치하지 않습니다.

또한 업데이트 또는 삭제시 특정 동작을 가정 할 수있는 옵션이 없습니다. 외래 키가 있는지 여부에 관계없이 원하는 작업을 수행하려면 코드를 작성해야합니다. 삭제되지 않았을 때 연속으로 삭제한다고 가정하면 삭제가 실패합니다. 참조 된 열에 대한 업데이트가 참조 행에 전파되지 않은 경우 전파되는 것으로 가정하면 업데이트가 실패합니다. 코드 작성을 위해 이러한 기능이 없을 수도 있습니다.

이러한 기능이 켜져 있으면 코드에서 기능을 에뮬레이트하므로 약간의 성능이 저하됩니다.

따라서 요약 .... 일관된 데이터베이스가 필요한 경우 외래 키가 필수적입니다. 외래 키는 사용자가 작성하는 코드에 존재하거나 작동한다고 가정해서는 안됩니다.


1

나는 Dmitriy의 대답을 에코합니다.

FK가 종종 가져 오는 성능 오버 헤드에 대해 걱정하는 사람들을 위해, Oracle에서는 삽입, 삭제 또는 업데이트 중에 제약 조건 유효성 검사의 비용 오버 헤드없이 쿼리 최적화 프로그램 FK 제약 조건을 활용할 수있는 방법이 있습니다. 이는 RELY DISABLE NOVALIDATE 속성을 사용하여 FK 제약 조건을 만드는 것입니다. 이는 쿼리 최적화 프로그램이 데이터베이스가 실제로 제약 조건을 적용하지 않고 쿼리를 작성할 때 제약 조건이 적용되었다는 것을 의미합니다. FK 제약 조건으로 테이블을 채울 때 제약 조건을 위반하는 것처럼 FK 열에 제약 조건을 위반하는 데이터가 없는지 확인하려면 책임을 져야합니다. 이 FK 제약 조건이있는 테이블과 관련된 쿼리에서 신뢰할 수없는 결과를 얻을 수 있습니다.

나는 보통이 전략을 내 데이터 마트 스키마의 일부 테이블에 사용하지만 통합 스테이징 스키마에는 사용하지 않습니다. 데이터를 복사하는 테이블에 이미 동일한 제약 조건이 적용되었거나 ETL 루틴이 제약 조건을 적용하는지 확인합니다.


1

여기에 응답하는 많은 사람들이 참조 제한 조건을 통해 구현 된 참조 무결성의 중요성에 너무 매달 렸습니다. 참조 무결성을 가진 큰 데이터베이스에서 작업하는 것은 성능이 좋지 않습니다. Oracle은 계단식 삭제에서 특히 나쁜 것 같습니다. 제 경험에 따르면 응용 프로그램은 데이터베이스를 직접 업데이트해서는 안되며 저장 프로 시저를 통해 이루어져야합니다. 이렇게하면 코드베이스가 데이터베이스 내부에 유지되므로 데이터베이스의 무결성이 유지됩니다.

많은 응용 프로그램이 데이터베이스에 액세스하는 경우 참조 무결성 제약 조건으로 인해 문제가 발생하지만 이는 제어에 달려 있습니다.

응용 프로그램 개발자는 데이터베이스 개발자가 반드시 익숙하지 않은 요구 사항과 매우 다른 요구 사항을 가질 수 있다는 점에서 더 큰 문제가 있습니다.


5
"응용 프로그램은 데이터베이스를 직접 업데이트하지 않아야하며 저장 프로 시저를 통해 이루어져야합니다. 이렇게하면 코드베이스가 데이터베이스 내부에 유지되므로 데이터베이스의 무결성이 유지됩니다." <-여기에는 저장 프로 시저의 논리가 데이터 무결성을 위반할 수 없다는 가정이 있습니다. 이는 명백한 잘못입니다.
Tim Gautier

1

당신이 절대적으로 확신한다면, 미래의 기본 데이터베이스 시스템이 변경되지 않을 것이라고 외래 키를 사용하여 데이터 무결성을 보장 할 것입니다.

그러나 외래 키를 전혀 사용하지 않는 또 다른 실제적인 이유는 다음과 같습니다.

다른 데이터베이스 시스템을 지원해야하는 제품을 개발 중입니다.

많은 다른 데이터베이스 시스템에 연결할 수있는 Entity Framework를 사용하는 경우 "오픈 소스 무료"서버리스 데이터베이스를 지원할 수도 있습니다. 이러한 모든 데이터베이스가 외래 키 규칙 (행 업데이트, 삭제 등)을 지원하지는 않습니다.

다른 문제가 발생할 수 있습니다.

1.) 데이터베이스 구조를 만들거나 업데이트 할 때 오류가 발생할 수 있습니다. 외부 키는 데이터베이스 시스템에서 무시되기 때문에 자동 오류 만있을 수 있습니다.

2.) 외래 키를 사용하는 경우 비즈니스 논리에서 데이터 무결성 검사를 거의 또는 전혀 수행하지 않을 수 있습니다. 이제 새 데이터베이스 시스템이 이러한 외래 키 규칙을 지원하지 않거나 다른 방식으로 동작하는 경우 비즈니스 논리를 다시 작성해야합니다.

다른 데이터베이스 시스템이 필요한 사람은 누구입니까? 글쎄, 모든 사람이 자신의 컴퓨터에서 완전히 날아간 SQL-Server를 감당할 수 있거나 원하는 것은 아닙니다. 이 소프트웨어는 유지 관리해야합니다. 다른 사람들은 이미 다른 DB 시스템에 시간과 돈을 투자했습니다. 서버리스 데이터베이스는 한 대의 컴퓨터에서만 소규모 고객에게 적합합니다.

이러한 DB 시스템이 모두 어떻게 작동하는지는 아무도 모르지만 무결성 검사를 통한 비즈니스 로직은 항상 동일하게 유지됩니다.


0

나는 항상 그것들을 사용하지 않는 것이 게으른 줄 알았습니다. 나는 항상 이루어져야한다는 것을 배웠다. 그러나 나는 Joel의 토론을 듣지 않았습니다. 그는 그럴만한 이유가 있었을 지 모르겠다.


토론보다는 커프스 비평 이었지만, 나는 그가 주제에 대해 독립적으로 생각하는 것을 정확하게 연구해야 할 것입니다! 그러나 나는이 주제에 대한 공동체의 의견에 대해서도 궁금했다.
ljs

0

FK로 인해 문제가 발생할 수있는 경우는 키를 더 이상 사용할 수 없지만 조회 테이블에서 키를 참조하는 기록 데이터가있는 경우입니다.
분명히 해결책은 일을 더 잘 디자인하는 것이지만, 나는 당신이 항상 완전한 솔루션을 통제하지 못하는 실제 상황을 생각하고 있습니다.
예를 들어, customer_type다른 유형의 고객을 나열 하는 룩업 테이블이있을 수 있습니다. 특정 고객 유형을 제거해야하지만 비즈니스 제한으로 인해 클라이언트 소프트웨어를 업데이트 할 수 없으며 아무도이 상황을 조사하지 않았다고 가정하겠습니다. 소프트웨어를 개발할 때 다른 테이블에서 외래 키라는 사실은 해당 소프트웨어를 참조하는 기록 데이터를 알지 못하더라도 행을 제거하지 못하게 할 수 있습니다.
이로 몇 번 화상을 입은 후에는 관계의 db 시행에서 멀어 질 것입니다.
(나는 이것이 좋다고 말하지는 않는다-FK와 db 제약을 피하기로 결정한 이유를 제시 할뿐)


당신이 말하려는 것을 이해한다면, 그에 대한 나의 대답은 룩업 테이블의 레코드를 논리적으로 삭제하거나 더 이상 관련이없는 기록 데이터를 아카이브하고 룩업 레코드도 아카이브하는 것이라고 생각합니다.
Chad
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.