본문 바로가기
  • 오늘도 한걸음. 수고많았어요.^^
  • 조금씩 꾸준히 오래 가자.ㅎ
카테고리 없음

[sql] 데이터베이스 키 개념, 기본키, 외래키 등

by 미노드 2023. 7. 12.

키의 종류 

키는 관계형 데이터 모델에서 특정 레코드를 식별하기 위해 사용한다. 두 개 이상의 필드로 구성된 키를 복합키라고 한다. 키의 종류에는 슈퍼키, 후보키, 기본키, 외래키, 대체키가 있다.
 네이버 지식백과 키의종류

수퍼키 

- 레코드들을 식별할 수 있는 ‘필드의 집합’ (유일성)
- 테이블은 적어도 1개의 슈퍼키를 가져야 한다.
- 수퍼키 정의

후보키

- 슈퍼키에서 레코드를 식별할 수 있는 최소한의 필드만 남겨놓은 집합 (유일성, 최소성)
- 후보키 정의
- 슈퍼키 { 학번, 학생이름, 학과 } 집합은 학번만으로도 레코드를 식별할 수 있으므로 부분집합 중 { 학번 } 집합만 후보키가 될 수 있다.

기본키(Primary Key)

- 설계자가 여러 후보키 중 하나를 선택하여 정의한 식별자 (유일성, 최소성)
- 기본키의 모든 필드의 값은 null 이 될 수 없다.
- 기본키 정의

외래키(Foreign Key)

- 다른 테이블의 기본키를 참조한다.
- 외부 테이블에서 기본키이거나 유일해야 한다.
- 외래키의 모든 필드는 참조하는 기본키와 동일한 도메인(값의 종류&범위)을 갖는다.
- 외래키의 모든 필드의 값은 참조하는 기본키와 동일하거나 null 이다.
- 외래키 정의

대체키

- 기본키로 선택되지 못한 후보키들이다. 
- 이름에서 알 수 있듯이 대체키는 기본키를 대신할 수 있지만 기본키가 되지 못하고 탈락한 이유가 있을 수 있다. 
- 기본키를 선택할 때 고려할 사항을 하나씩 따져보면 기본키의 [주소 속성이 추가된 릴레이션의 예]의 고객 릴레이션은 고객아이디 속성을 기본키로 선택하는 것이 무난하다. 
- 따라서 기본키로 선택되지 못한 (고객이름, 주소) 속성 집합이 대체키가 된다. 

* 기본키와 외래키에 대한 추가적인 의견

특히 기본키와 외래키를 많이 접할텐데,
기본키(컬럼)는 테이블1을 만들 때 하나만 선언할 수 있다. 
해당 테이블1의 구분인자로써 사용될 수 있다.

다만 외래키를 사용하는건 검토를 하고 사용하는게 좋아 보인다
외래키는 다른 테이블2의 기본키를 가져와서 값으로 삼는 것인데,
이를 통해 관계형 데이터베이스 에서 테이블1과 테이블2이 1:n으로 연결된다고 한다.
그런데 굳이 외래키를 연결하지 않더라도 쿼리에서 조합해 데이터를 저장시키는게 가능하다는 것...
외래키를 등록해서 테이블1에 들어가는 값이 테이블2에 속해있지 않으면 입력되지 않도록 할 수 있다.

예시를 들어보자.

테이블 1. 학생의 수업 리스트이다.

id 학생명 강의명 강의코드
1 개똥이 병충해 방지기법 1231
2 길동이 분신술 4242
3 말똥이 축산업 개론 2323

테이블 2. 강의 리스트이다.

강의코드 강의명 교수
1231 병충해 방지기법 김개동
4242 분신술 나루도
2323 축산업 개론 이말동

테이블1에선 학생이 어떤 수업을 듣는지 알 수 있다.
그러나 강의를 하는 교수의 이름은 알 수 없다.

이를 알려면 테이블2를 조회해서 교수의 이름을 확인해야 한다.
개똥이가 듣는 강의의 교수 이름을 알고싶다면, 테이블2를 참조해야하는데 여기서 강의코드 1231을 사용할 수 있다.

테이블1에서 강의코드를 사용해 테이블2를 참조할 수 있는 것이다.
여기서 테이블1의 강의코드를 외래키로 볼 수 있다.

※ 외래키의 목적, 왜쓰나? 귀찮은데

- 외래키는 무결성을 유지하기 위해 사용한다

무결성이란 현재 데이터베이스에 존재하는 값이 틀리지 않았다는 것을 의미합니다.
현재 4자리 숫자로 이루어진 강의 코드에 알파벳을 추가하여 확장하려고 한다면,
테이블2를 참조하고 있는 모든 테이블들(테이블1 등)에 포함된 강의 코드를 모두 수정해줘야 합니다.

담당자가 깜빡하고 테이블1의 강의 코드를 수정하지 못했다면 학생으로부터 테이블2를 참조할 수 없게 되며,
이를 사용하는 프로그램에서 오류가 발생합니다.
만약 테이블1의 강의 코드를 외래 키로 만들면서 'ON UPDATE CASCADE'라는 옵션을 추가해주었다면
강의 코드를 참조하는 모든 테이블의 강의 코드가 함께 수정되기 때문에 해당경우에 대처가 쉽습니다.

이처럼 어떤 키를 수정(ON UPDATE, 이하 MySQL기준) 또는 삭제(ON DELETE)하려고 할 때 다른 곳에서 해당 키를 참조하고 있다면

* 키 자체를 수정, 삭제 못하도록 막거나(RESTRICT)
* 참조하는 테이블 에서도 모두 함께 수정, 삭제되도록 할 수 있습니다(CASCADE).
* 또는 참조하는 테이블에서 해당 키의 값을 NULL로 바꿔줄 수도 있습니다(SET NULL)

이렇게 외래 키를 사용하면 꼬이고 꼬인 테이블들의 데이터들이 모두 무결성을 갖추도록 할 수 있습니다.

※ 외래키 굳이 안써도된다. 아니 오히려 안쓰는게 낫다?

실제로 외래키를 쓰는게 맞아 보이는 환경에서 외래키를 쓰지 않는 곳도 존재한다.
프로그래밍 단에서 정합성을 유지하는 로직이 존재한다면 굳이 외래키 참조 설정을 넣을 필요가 없다.

또한, 동적으로 테이블을 생성하는 경우 외래키를 많이 사용할수록 데이터베이스가 더 복잡해지며, 유지보수도 어려워진다.

한마디로 불편하고 구분이 더 어려워진다.
RESTRICT나 CASCADE 옵션을 사용함으로써 나도모르게 데이터가 변경되는 일이 발생하여 일이 어려워지는 경우도 있다.

실수로 테이블의 값이 변경되었을 때, CASCADE의 영향으로 참조하는 테이블들의 값이 모두 변경된다면 이슈가 된다.
데이터 보존이 중요한 상수 테이블일 경우 외래키로 참조를 안하는게 더 나을수도 있다.

그러나 DB단에서 외래키를 사용하지 않는다는 것은, 프로그래밍 단에서 보장할진 몰라도
DB에서 무결성 및 정합설을 보장하지 않는다는 뜻이다.

매번 무결성 검사를 하는 과정에서 속도, 성능 저하가 발생한다 해도, 무결성이 유지될 필요가 있다면 외래키를 사용하는게 맞다.
그러나  무결성, 정합성을 희생시켜 개발 편의와 안정성, 확장성을 보장 하려면 외래키를 쓰지 않는게 낫다.

※ 외래키의 대체, 인덱스만 만들어 쓰기

인덱스란 데이터베이스의 접근 속도를 높이기 위해, 자주 사용되는 속성에 대해서 별도의 인덱스 테이블을 만들어 해당 위치를 빠르게 찾기 위해 사용한다.

상수테이블에 인덱스를 지정하여 참조시키면 외래키의 기능을 대체할 수 있다.

id 학생명 강의명 강의코드
1 개똥이 병충해 방지기법 1231
2 길동이 분신술 4242
3 말똥이 축산업 개론 2323

보통 기본키와 외래 키에 대해서는 자동으로 인덱스 테이블이 생성되기 때문에 별도로 인덱스를 만들어줄 필요가 없다.
하지만 개념상 외래 키에 해당하는 속성을 외래 키로 설정하지 않고 사용하는 경우
검색 속도를 높이기 위해 별도의 인덱스를 만들어 주는게 좋다.

대신 외래 키 테이블을 수정하는 경우에는 외래 키를 참조하는 테이블들의 값들도 수정해줘야 한다.
이 작업을 로직을 미리 만들어서 값의 변경이 있을때 무결성을 보장할 수도 있다.
이런 수고가 외래키를 등록해 사용하는 것보다 나을지 아닐지 판단하고 사용하면 된다.