# Key

데이터베이스의 키: 특정 레코드를 식별하거나 검색하기 위해 사용되는 필드 또는 속성

* DB내 각 레코드를 고유하게 식별
* 레코드 간의 관계 구성 시 사용

***

\


## ︎ Key의 종류

\


### 슈퍼 키 (Super Key)

한 테이블 내에 있는 속성들의 집합으로 구성된 키

*   유일성은 만족시키지만 최소성은 만족시키지 못 함

    ex) (학생번호 + 이름)으로 묶어서 키를 구성했을 경우,

    (1번 홍길동), (2번 홍길동)과 같이 동명이인 구별가능 → 유일성 만족

    두개의 속성(학생번호, 이름)을 이용 → 최소성 만족X
* 두 속성을 하나로 묶어 슈퍼 키로 만들 수 있음
* 어떤 속성끼리 묶던 중복값이 안나오고 서로 구별가능할 수 있으면 됨

\


### 후보 키 (Candidate Key)

테이블에서 기본 키로 선택될 수 있는 모든 키

* 테이블을 구성하는 모든 튜플에 대해 유일성과 최소성을 만족해야 함
* 후보 키는 중복되지 않음
* NULL값을 가질 수 없음
* 유일성과 최소성 만족

\


### 기본 키 (Primary Key)

테이블에서 각 행을 고유하게 식별하는 역할을 하는 키

후보 키 중 선정된 Main Key로 테이블에서 특정 튜플을 유일하게 구별할 수 있는 속성

* 기본 키는 중복될 수 없음
* NULL값을 가질 수 없음
* 대부분의 DBMS는 자동으로 기본 키 값을 생성하는 기능 제공

\


### 대체 키/보조 키 (**Alternate Key)**

후보 키 중에서 기본 키로 선택되지 않은 키

\


### 외래 키 (**Foreign Key)**

다른 테이블의 기본 키를 참조하는 속성 또는 속성들의 집합

* 테이블 간의 참조 관계를 표현

\


### 복합 키 (Composit Key)

각 튜플들을 식별할 수 있는 두 개이상의 속성으로 구성된 후보 키

ex) 학생들의 수강과목 테이블의 경우 (속성: 학번, 과목번호, 학점)

한 학생이 여러과목을 수강할 수 있고, 각 과목도 여러학생이 수강한다. 따라서 학번+과목번호이 후보키가 된다. 이처럼 단일 키 만으로 튜플을 구분할 수 없을 때 사용한다.

* 후보 키, 대체 키, 기본키 모두 복합 키일 수 있다.\
  ( 이는 복합 키가 최소성을 만족함을 의미 )

\


***

### Q. 기본 키는 수정이 가능한가?

\
A. 기본 키(PK)의 속성은 변경할 수 없다!

레코드를 고유하게 식별하는데 사용되는 식별자로써 중복되거나 변경되면 데이터의 일관성과 무결성을 위협할 수 있기 때문이다.

따라서 수정하기 위해서는 삭제 후 다시 생성해야한다.

```sql
/* 1. PK 삭제 */
ALTER TABLE 테이블 명 DROP CONSTRAINT 삭제할 기본 키

/* 2. PK에 추가할 컬럼의 NOT NULL 속성 추가 */
ALTER TABLE 테이블 명 ALTER COLUMN 새로운 컬럼 VARCHAR(10) NOT NULL

/* 3. PK 재생성 */
ALTER TABLE 테이블 명 ADD CONSTRAINT 새로 설정할 기본 키 이름 PRIMARY KEY (새로운 컬럼)
```

*   기본 키의 생성 시점

    일반적으로 기본 키는 테이블에 레코드를 삽입할 때 생성이 된다. 따라서 생성 후 에는 변경하지 않는 것이 좋다.

***

### Q. 사실 MySQL의 경우, 기본키를 설정하지 않아도 테이블이 만들어집니다. 어떻게 이게 가능한 걸까요?

\
A. MySQL은 기본적으로 InnoDB 스토리지 엔진을 사용하며, InnoDB 스토리지 엔진은 기본 키가 없는 테이블을 생성할 수 있도록 허용하기 때문이다.

InnoDB 스토리지 엔진은 테이블에 대해 클러스터화된 인덱스를 사용한다. 따라서 기본 키를 설정하지 않으면 InnoDB는 내부적으로 테이블에 임시적인 물리적인 기본 키를 생성하여 클러스터드 인덱스를 구성한다. 해당 임시 기본 키는 행이 삽입될 때마다 자동으로 증가하는 숫자로 구성되며, 데이터의 물리적인 순서를 지정한다.

Mysql 뿐 만 아니라 다른 데이터베이스 시스템도 임시적으로 기본 키를 생성해서 테이블을 생성할 수 있다. 하지만 데이터의 고유성이 보장되지 않으므로 권장하지 않는다.

***

### Q. 외래키 값은 NULL이 들어올 수 있나요?

\
A. 외래키 값에 NULL이 올 수 있다. 다른 테이블의 기본 키를 참조할 때 참조되는 값이 존재하지 않을 때 NULL 값이 할당 된다.

* NULL값이 외래 키 컬럼에 할당된 경우
  * 해당 레코드가 다른 테이블의 어떤 행과도 연관되어 있지 않음을 나타냄
  * 참조 무결성 제약 조건에 의해 해당 외래 키를 가리키는 레코드는 삭제되거나 수정될 수 없음

만약 외래 키에 NULL값을 허용하지 않도록 추가 제약조건을 걸 경우 외래 키 컬럼에 null값이 허용되지 않으며 항상 유효한 참조를 가져야한다.

*   NULL 값이란?

    **데이터베이스 내의 데이터 값이 존재하지 않는다는 것을 지시하는데 사용되는 특별한 표시어**

***

### Q. 어떤 칼럼의 정의에 UNIQUE 키워드가 붙는다고 가정해 봅시다. 이 칼럼을 활용한 쿼리의 성능은 그렇지 않은 것과 비교해서 어떻게 다를까요?

\
A. 검색, 중복 검사 성능은 향상, 삽입/수정/삭제 성능은 저하

UNIQUE 키워드가 붙은 컬럼의 값은 유일해야하며 중복 값을 허용하지 않는다.

* 검색 성능
  * UNIQUE 키가 있는 컬럼 검색 시 데이터베이스는 해당 컬럼에 대한 인덱스를 생성한다. 해당 인덱스를 사용하므로 검색성능이 향상된다.
* 중복 검사 성능
  * UNIQUE 키워드 자체가 컬럼값이 유일하며 중복 값을 허용하지 않는다는 것을 의미함으로 중복여부를 빠르게 확인할 수 있다. UNIQUE키가 없다면 해당 컬럼을 순차적으로 스캔하며 중복여부를 확인해야함으로 성능저하를 초래할 수 있다.
* 삽입/수정/삭제 성능
  * UNIQUE 키가 있는 칼럼의 경우 새로운 값의 삽입,수정,삭제와 같이 기존의 값이 변경될 때 데이터베이스는 UNIQUE 제약조건을 검사해야한다. 이는 추가적인 비교, 검증작업을 수행함으로 성능저하를 일으킬 수 있다.

***

### Q. 자연 키와 대체 키 중 어떤 키를 기본 키로 선택하면 좋을 지?

\
A. 대체 키를 기본 키로 사용하는 것이 권장된다.

자연 키 : 테이블을 이루는 컬럼 가운데 의미를 담고 있는 후보 키\
대체 키 : 임의의 식별번호로 이루어진 후보 키

*   유연성과 유지보수성

    도메인에서 발생하는 속성을 사용한 자연 키의 경우 비즈니스 규칙이나 요구사항이 변경될 경우 유연성과 유지보수성에 제약을 줄 수 있다. 하지만 대체 키의 경우 비즈니스 도메인과 관계가 없기때문에 유연성과 유지보수성 측면에서 자연 키보다 우수하다.
*   성능

    자연 키는 비즈니스적 의미를 가지기 때문에 길거나 복잡한 값을 가질 수 있다. 이는 인덱스를 생성하거나 join연산을 수행할때 성능에 영향을 미칠 수 있다. 하지만 대체 키는 단순하고 일관된 형태를 가져 성능상 이점을 가진다.
*   보안

    자연 키의 경우 개인 식별 정보를 포함할 수 있어 보안에 취약할 수 있다. 이에 반해 대체 키는 개인 정보 보호 측면에서 더욱 안전하다.

***

### JPA에서의 기본 키 생성

&#x20;`@GeneratedValue` 어노테이션을 JPA엔티티의 기본키 필드 위에 붙이면, 기본키를 자동으로 생성해주는 전략을 사용할 수 있다.

* @GeneratedValue(strategy = GenerationType.IDENTITY)
  * 기본키 생성을 hibernate 가 아닌 데이터베이스가 하도록 위임
  * 자동 증가 기능을 사용하여 기본 키 값 생성
  * 주로 Mysql, PostgreSQL, SQL Server, DB2에서 사용
* @GeneratedValue(strategy = GenerationType.SEQUENCE)
  * 데이터베이스 시퀀스를 사용하여 기본 키 값을 생성
  * 주로 Oracle에서 사용
* @GeneratedValue(strategy = GenerationType.TABLE)
  * 데이터베이스에 키 생성을 위한 별도의 키 생성 테이블 사용
  * 모든 데이터베이스에서 사용 가능하며 시퀀스 기능을 지원하지 않는 데이터베이스에 유용
* @GeneratedValue(strategy = GenerationType.AUTO)
  * 기본 키를 자동으로 생성하는 전략
