도당탕탕

Effective-SQL Better-Way-1 : 모든 테이블의 기본키가 있는지 확인하자 본문

Database

Effective-SQL Better-Way-1 : 모든 테이블의 기본키가 있는지 확인하자

backlo 2020. 8. 31. 20:35

관계형 모델은 각 테이블의 로우를 구분할 수 있는 한개 이상의 기본키가 있습니다. 그리고 해당 기본키는 다음과 같이 속성을 가지고 있습니다.

  1. 로우마다 유일 해야 한다.
  2. 널 값을 가질 수 없다.

여기서 궁금한점! 만약 기본키가 없으면 어떻게 될까요? 기본키를 만들지 말고 테이블을 구성하면 안될까요?

결론적부터 말씀드리면 관계형 모델링에서 할 수는 있지만 해서는 안됩니다.

그 이유는 다음과 같이 문제가 발생합니다.

  1. 데이터를 걸러 낼 때 일치하는 로우가 없거나 딱 한 개인 조건은 보장할 수 없다.
  2. 로우마다 유일하다고 해서 데이터베이스 엔진이 컬럼 한 개나 일련의 컬럼을 항상 효율적으로 사용할 수 있는 것은 아니다.
  3. 기본키가 없는 테이블 간의 관계를 모델링하는 것은 일반적으로 불가능하다.
  4. 반복적이고 일관성 없는 데이터가 쌓여 쿼리 수행 속도가 느리고, 부정확한 정보를 조회하는 등 모든 종류의 문제를 일으킬 수 있다.

올바른 테이블 설계

Order리는 테이블에 일관성 없는 데이터가 있다고 예를 들어 봅시다.

| customer  |
-------------
|poo dodang |
|dodang Poo |
|do dang poo|
|poo do dang|

다음 테이블을 보면 모든 값이 유일한 것은 분명한 사실이나, 이들이 모두 다른 사람이라는 것은 보장 하지 못합니다. 실제로 보면, 전부 poododang 이름을 가진 동일 인물입니다. 이렇듯 컴퓨터는 사람보다 훨씬 빠르게 데이터를 처리할 수 있지만, 상당한 양의 프로그래밍 없이는 언제 특정 데이터를 동일한 것으로 간주해야 할지 판단하는 작업을 잘 처리하지 못합니다.

또한 customer 컬럼을 기본키로 정의 할 수 있지만 유일한 값을 가져야 한다는 요구 사항을 만족시키더라도 바람직한 선택은 아닙니다.

그렇다면 무엇이 기본키의 후보 자격이 될수 있을까요??

  1. 유일한 값을 가져야한다.
  2. 널 값을 가질 수 없다.
  3. 안정적인 값이어야 한다. (갱신 x)
  4. 가능한 한 간단한 형태여야 한다. (문자형보단 정수형, 복합 컬럼보단 단일 컬럼)

즉 일반적인 방법은 의미 없는 숫자 데이터로 자동 생성되는 컬럼을 기본키로 만드는 것입니다. 소프트웨어에 따라 이 컬럼은 여러 이름으로 칭하는데 DB2, SQL Server, Oracle 12c 는 IDENTITY, Access에서는 AutoNumber, MySQL에서는 AUTO_INCREMENT, PostgreSQL에서는 serial 컬럼이라고 합니다. 오라클 12c 이전버전에는 동일한 기능을 구현 하려면 컬럼 속성이 아닌 독립적인 SEQUENCE 객체를 사용해야 했습니다. 또한 DB2, SQL Server, PostgeSQL에서도 SEQUENCE 객체를 지원합니다.

참조 무결성

관계형 데이터베이스에서 참조 무결성은 아주 중요한 개념입니다. 참조 무결성을 준수한다는 것은 널이 아닌 외래키가 설정된 자식 테이블의 각 레코드와 일치하는 레코드가 부모 테이블에 존재한다는 것을 의미합니다.

테이블 간의 참조 무결성을 유지하려면 변경된 기본키 값을 이와 관련 있는 테이블과 모든 자식 레코드에 전파해야 합니다. 이렇게 갱신이 전파되면 관련 테이블에 잠금이 설정되어 높은 동시성을 지원하는 다중 사용자 데이터베이스에서 심각한 문제를 일으킬 수 있습니다.

다음 예를 보죠

| CustomerID | CustomerName | CustomerAge | CustomerAddress |
-------------------------------------------------------------
| al         | Alice        | 25          | Seoul           |
| bo         | Bob          | 30          | Seoul           |
| ch         | Charlie      | 45          | Seoul           |
| da         | David        | 29          | Seoul           |

이 예제는 텍스트 기반 기본키인 CustomerID는 CustomerName과 연관된다는 것이 비즈니스 규칙이라고 가정합니다. 만약 이름을 수정한다면 Id도 갱신해야합니다. 그리고 기본키 값이 변경되므로 관련된 테이블에도 모두 변경이 전파되어야 합니다. 하지만 의미 없는 값을 키로 사용한다면 Id값을 변경하거나 갱신할 필요가 없을 뿐더러 변경된 내용을 전파할 필요도 없습니다.

텍스트 기반 컬럼의 기본키 vs 자동 생성된 숫자의 기본키 vs 복합 기본키

텍스트 기반 컬럼의 기본키는 자동 생성된 숫자의 기본키와 비교해서 다음과 같은 장점이 있습니다.

  1. 중복 값 입력을 막을 수 있다.
  2. 참조 테이블과 조인할 필요가 없어 SQL문이 간략하다.

하지만 다음과 같은 단점도 있죠.

  1. 중복을 가지고 있으면 안되기 때문에 이름으로 기본키로 설정할 경우 동명이인의 이름을 넣을 수 없다.
    • 유일 인덱스를 추가해 이름이 중복되지 않게 하는 것이 더 쉽다.
  2. 많은 고민을 하고 기본키로 설정해야 한다.

그래서 데이터베이스의 전문가 사이에서도 큰 이견이 있습니다. 책에서도 이런 논쟁에서 어느 한쪽만 편을 들지는 않을 것입니다. 하지만 한가지 핵심은 기본키로 사용하는 컬럼은 반드시 유일한 값을 가져야 한다는 점입니다. 또한 복합 기본키는 다음 두가지 이유에서 효율성이 떨어지므로 사용하지 않는 것이 좋습니다.

  1. 기본키를 정의할 해당 컬럼에 유일 인덱스를 같이 만든다. 컬럼 두 개 이상에 유일 인덱스를 만들 경우 데이터베이스 시스템의 할 일이 많아져 성능 저하가 발생한다.
  2. 일반적으로 기본키로 조인을 수행하는데, 기본키가 여러 컬럼으로 구성되어 있으면 쿼리가 좀 더 복잡하고 느려진다.

물론 특정한 상황에서 여러 컬럼을 기본키로 사용하는 것은 마땅합니다. 예를 들어 제품과 판매 회사를 연결하는 복합테이블이 있습니다. 이 복합테이블은 ProductId와 VendorId를 복합키로 가지고 있고 주 공급처 인지 부 공급처인지, 판매 회사가 부과하는 제품 가격 컬럼 등 구성 할 수 있습니다. 물론 인위적으로 기본키를 생성 할 수 있지만, 복합 기본키를 정의하는 것이 해당 테이블을 표현하는데 더 의미가 있어 복합 기본키를 사용하는 것이 더 좋습니다.

Comments