다음과 같은 응급실 다이어그램이 있다고 가정 해보십시오.
이제 School
in 의 외래 키를 사용하여 관계를 나타내는 경우 a
가 a 에 속할 필요가 없기 때문에 값을 Student
가질 수 있습니다 .NULL
Student
School
따라서 올바른 방법은 (내가 읽은 내용을 기반으로) 관계를 나타내는 교차 테이블을 만드는 것입니다.
이런 식으로 NULL
테이블에 값을 표시 할 수 없습니다 School_has_Student
.
그러나 교차 테이블을 생성하는 대신 널 입력 가능 외래 키를 사용하면 어떤 단점이 있습니까?
편집하다:
나는 실수로 ( school_id
, student_id
)를 School_has_Student
테이블 의 기본 키로 선택 하여 관계를 다 대다로 만들었습니다. 올바른 기본 키는 다음과 같아야합니다 student_id
.
답변
두 모델은 서로 다른 관계를 나타냅니다.
조인 테이블을 사용하여 다 대다 관계를 모델링합니다.
간단한 외래 키를 사용하여 일대 다 관계를 모델링합니다.
널 입력 가능 외래 키의 단점은 달성하려는 경우 다 대다 관계를 모델링 할 수 없다는 것입니다.
질문에 대한 편집 내용을 바탕으로 학생용 테이블을 동일한 키를 가진 두 개의 테이블로 효과적으로 분할합니다. 나는 일반적으로 너무 많은 필드가있는 테이블에서 이것을 보았습니다. 따라서 누군가가 더 관리하기 쉽도록 두 개로 나눕니다 (돈에 립스틱을 바르는 것입니다).
학생 테이블을 분할하면 두 번째 테이블에 레코드가 없어도되므로 두 번째 테이블을 선택적으로 만들 수 있습니다. 이것은 널이 될 수 있기 때문에 설정할 필요가없는 필드와 매우 유사합니다.
일대 다 관계를 원한다면 단일 테이블을 사용하고 학생 테이블에서 학교 ID를 null로 허용하는 것이 훨씬 좋습니다. 외래 키의 경우에도 필드에서 null을 피할 이유가 없습니다. 이는 외부 관계가 선택 사항임을 나타냅니다. 개발자와 DBA는이를 명확하게 이해하고 기본 데이터베이스 엔진은 확실히 작동해야합니다.
조인이 걱정 되더라도 걱정하지 마십시오. 조인이 null 필드와 작동하는 방식에 대한 정의가 잘 정의되어 있습니다. 단일 테이블을 사용하면 3 개 대신 2 개의 테이블을 조인 할 수 있습니다.
답변
당신은 위의 의견을 썼습니다 :
외래 키 열에 NULL 값이 많은 경우 교차 테이블을 사용하는 것이 좋습니다 (예 : 직원의 98 % 인 경우) 부서를 관리하지 마십시오)
외래 키 열에 NULL 값이 많으면 프로그램에서 처리하는 각 레코드마다이 빈 열을 처리해야합니다. 열은 모든 경우의 98 %에서 비어 있지만 일부 디스크 공간을 차지할 것입니다. 관계를 쿼리한다는 것은 해당 열을 쿼리하여 더 많은 네트워크 트래픽을 제공하고 ORM을 사용하는 경우 테이블에서 클래스를 생성하는 경우 프로그램을 의미합니다 또한 클라이언트쪽에 필요한 것보다 많은 공간이 필요합니다. 교차 테이블을 사용하면이를 피할 수 있으며, 그렇지 않으면 동등한 외래 키가 NULL이 아닌 경우 필요한 링크 레코드 만 있습니다.
반대로, NULL 값이 몇 개가 아닌 경우 50 % 이상의 관계가 NULL이 아니라고 가정하면 교차 테이블을 사용하면 디스크 공간이 많고 복잡성이 높아져 네트워크 트래픽이 증가하는 등의 반대 효과가 나타납니다.
따라서 교차 테이블을 사용하는 것은 최적화의 한 형태 일 뿐이며, 특정 경우에만, 특히 요즘에는 디스크 공간과 메모리가 저렴 해지고 훨씬 덜 자주 필요한 오늘날에만 합리적입니다. “데이터베이스 시스템의 기초”는 원래 20 년 이상 전에 작성되었으며 (1994 년부터 두 번째 버전에 대한 참조를 찾았습니다), 당시에는 권장 사항이 이미 있었다고 생각합니다. 1994 년 이전에는 대용량 스토리지가 여전히 비싸고 컴퓨터와 네트워크가 오늘날보다 훨씬 느리기 때문에 공간 최적화가 오늘날보다 훨씬 더 중요했을 것입니다.
까다로운 의견에 대한 부수적 인 설명으로, 위의 진술은 “데이터베이스 시스템의 기초”의 저자가 자신의 권장 사항을 염두에두고 생각한 것을 예상하려고 노력하고 있습니다. 일부 데이터베이스에는 교차 테이블을 사용하지 않는 “스파 스 열”과 같은 다른 최적화가 있습니다.
따라서 그 추천을 잘못하지 마십시오. 이 책은 {0,1}:n
일반적으로 관계에 대한 교차 테이블을 선호 하거나, 당신이 쓴 것처럼 이것이 “올바른 방법”이라고 말하지 않습니다 . 이와 같은 최적화를 사용하면 실제로 필요할 때만 프로그램을 더 복잡하게 만들 수 있습니다.
답변
개념 모델 인이, 모양을 매우 정통 덜 말 :
실제 모델은 다음과 같이 보일 것이며 , 덜 말하면 혼란 스러울 것입니다.
나의 제안:
대부분의 학생들에게 적용되지 않는 많은 열 (FK 또는 기타)이있는 경우 테이블을 1 : 1 관계로 역할 테이블로 분리하십시오. 그러나 이는 FK이기 때문에 열이 대부분의 행에 적용되지 않기 때문입니다.
그렇지 않으면 , 널 (NULL) FK는 데이터베이스의 정상적인 일부이며 테이블이 M에 대한 보통 가입 : M의 RELS.
1 : 1 관계의 일반적인 용도는 엔터티가 특정 유형 인 경우에만 적용되는 열이 있고 성능 또는 저장소 고려 사항에 대한 BLOB 열을 추출하는 역할 테이블에 사용됩니다. FK에서 널값을 피하는 것은 일반적인 사용법이 아닙니다.
답변
다른 답변 외에도 외래 키의 null 값이 모호하다는 것을 지적하고 싶습니다. 그것은 의미합니까?
1) 학생의 학교 (있는 경우)를 알 수없는 경우 ( ‘null’의 표준 의미-값을 알 수 없음)
2) 학생이 학교를 가지고 있는지 여부를 알고 있으며, 학교가 없다
null의 표준 의미를 사용하는 경우 외래 키 모델에서 “학생은 학교가 없습니다”를 어떻게 표현합니까? 이 경우, 학교 테이블에 ID가있는 “학교 없음”항목을 작성해야합니다. (이상적이지 않음)
답변
데이터베이스 테이블에는 제약 조건이라는 멋진 기능이 있습니다. 따라서 각 학생 중 1 명만 테이블에 표시 할 수있는 교차 테이블에서 테이블을 만드는 것이 매우 쉽습니다. 효과적으로 당신에게주는
이론은 훌륭하지만 결국 질문을 한 후에 데이터베이스를 모델링 할 것입니다.
“내 학생들이 어느 학교에 있는지”라는 질문으로 자주 질문하고 싶다면 전체 학생 테이블을 쿼리하거나 쉬운 교차 테이블을 원하십니까?
데이터베이스에서 : 질문에 최적화하십시오.
답변
세 번째 테이블을 사용하는 것이 실제로 의미가있는 사용 사례가 있습니다. 이 예는 순전히 가상적인 것처럼 보일 수 있지만, 그것이 나의 요점을 잘 설명해주기를 바랍니다. students
테이블 에 더 많은 열을 추가한다고 가정 하고 어느 시점에서 여러 열의 복합 인덱스를 통해 레코드에 고유성을 적용하기로 결정했습니다. school_id
열 을 포함해야 할 가능성이 매우 높으며 여기에서 문제가 발생하기 시작합니다. 방식 때문에 SQL은 여러 동일한 레코드를 삽입, 디자인 된 school_id
이다가 NULL
가능한 것입니다. 기술적 인 관점에서는 완벽하게 이해되지만, 직관적이지 않으며 예기치 않은 결과가 발생할 수 있습니다. 반면, 교차 테이블에서 고유성을 적용하는 것은 쉽습니다.
유일성 제약 조건이 타임 스탬프 열로 인해 발생한 “선택적”관계를 최근에 모델링해야했습니다. 테이블에 널 입력 가능 외래 키를 남겨두면 갑자기 동일한 타임 스탬프를 가진 레코드를 삽입 할 가능성이 생깁니다 (아직 감사하고 승인되지 않은 레코드에 설정된 기본 설정이라고 가정). 널 입력 가능 열.
보시다시피, 이것은 상당히 구체적인 경우이며 다른 사람들이 언급했듯이 대부분의 경우 모든 NULL
값을 완벽하게 사용할 수 있습니다 . 모델의 특정 요구 사항에 따라 다릅니다.
답변
이미 제출 된 많은 좋은 제안 외에도 개인적으로 나는 정말로 필요한 경우가 아니라면 외래 키의 팬이 아닙니다. 먼저 참조하는 M : M 관계가 있습니다. 또한 외래 키를 호출하여 해당 테이블 데이터를 쿼리로 가져 오면 테이블 크기에 따라 성능이 저하되고 복잡성이 증가합니다. 다른 사람들이 말했듯이, nullable FK 필드는 지원되지 않을 수 있으며 데이터 무결성 문제를 일으킬 수 있습니다.
학생 학교를 알 수 없거나 비어있는 주를 정의하는 경우 NULL은 이러한 조건을 구별하지 않습니다. (우리는 다시 데이터 무결성으로 돌아 왔습니다.) Tulains의 역할 테이블 제안은 우아하며 null 값을 깔끔하게 허용합니다.