본문 바로가기
Database/SQL

데이터 모델에 대한 좋은 방법

by oncerun 2022. 11. 26.
반응형

 

관계형 데이터베이스를 대상으로 데이터 모델을 설계할 때 정답은 없지만 정답에 가까운 방법은 존재한다. 

 

오늘 오전은 그 방법에 대해 정리하려고 한다.

 

1. 기본키는 필수인가?

 

관계형 모델은 하나의 레코드가 다른 레코드와 식별되어야 한다. 그렇기 때문에 모든 테이블에는 칼럼 한 개 이상으로 구분된 기본키가 있다.  

 

그런데 가끔 전달받은 데이터베이스의 테이블을 검토하다 보면 논리적으로 고유하다고 판단하여 PK 제약조건을 생성하지 않는 경우가 있다.

이는 상당히 위험해 보인다. 기본키 제약조건은 로우마다 유일한 값을 보장하며 null 값이 없다는 것을 보장해준다.

 

또 가끔 기본키 자체가 없는 경우가 존재한다.

 

물론 기본키 자체가 없는 테이블을 만드는 것도 규칙에 어긋나는 것은 아니다.

기본키가 없다고 해도 데이터베이스 엔진이 컬럼 한 개나 여러 칼럼을 항상 효율적으로 사용할 수 있는 것도 아니기 때문이다. 

그럼 우리는 효율적으로 사용하라고 데이터베이스 엔진에게  명령하면 되는 것이 아닐까? 

 

그때 우린 칼럼 한 개 이상을 기본키로 정의해 효율적으로 사용하라고 명령하면 된다. 

 

그리고 관계형 데이터베이스에서 근본적인 문제가 발생할 수 있다. 기본키 자체가 없는 경우 관계를 어떻게 표현할 것인가?

 

여기에 대한 정답은 테이블에 기본키가 없다면 자동 증분 되는 비즈니스에 종속되지 않는 값으로 만들자. 

 

나는 PostgreSQL을 사용하니 serial 칼럼을 사용한다. MySQL이라면 AUTO_INCREMENT, 오라클은 IDENTITY라고 한다.

 

여기서 왜 복합키를 추천하지 않냐고 하면 다음과 같은 이유가 있다.

 

  • 기본키 정의 시 대부분 데이터베이스는 해당 칼럼에 유일 인덱스를 같이 만든다. 칼럼이 두 개 이상에 인덱스를 만들면 데이터베이스가 해야 하는 일이 증가된다.
  • 조인 시 기본키를 사용하는데, 복합 키 인경우 쿼리가 복잡해지고 느려질 수 있다.

기본키가 정해졌다면 PK로 설정해 제약조건을 가지게 하자.

 

 

2. 단일 컬럼에 두 개 이상을 저장하고 싶다.

 

칼럼은 테이블이 대표하는 주제를 설명하는 유일한 특성이어야 한다.

 

두 개 이상의 값을 칼럼에 넣는 것은 좋은 생각이 아니지만 실무에서 " , " 로 구분하여 다중 값을 저장하는 것을 많이 볼 수 있다. 

이는 추가 요구사항을 반영하기 위해 테이블을 만들기 어렵거나 귀찮아서 그렇게 한 경우가 대부분일 것이다. 
또는 외부 데이터를 가져올 때 다중 값이 존재해 그대로 테이블에 때려 넣은 경우도 있다. 

 

나는 외부 데이터를 가지고 테이블을 만들어야 할 때 임시로 외부 리소스를 받을 수 있는 임시 테이블을 만들고 우선 데이터를 넣고 정합성을 검사한다. 

 

그 이후에 정규화된 테이블을 만들고 PL/SQL을 열심히 검색해 최대한 올바르게 설계된 테이블에 데이터를 다시 넣는 작업을 한다. 

물론 시간적으로 오래걸릴 순 있겠지만 이는 조회 시 많은 이점을 가져다준다. 
복잡한 조회 쿼리도 필요 없고, 애플리케이션 단 코드를 작성할 때도 매우 간편하게 처리할 수 있기 때문에 이 고생으로 애플리케이션 서버 리소스도 아끼고, 네트워크 비용도 아낄 수 있었다.

 

만약 한 컬럼에 여러 개의 값이 들어가면 검색하거나 값을 집계해야 할 때 값을 분리하기가 매우 까다로워진다. 

이러한 개별 특성은 자체 칼럼으로 분리하는 것을 고려해야 한다. 

 

그 이유는 다음과 같다.

  • 중복된 컬럼을 검색해야 할 때 where 조건절에 효율이 떨어지는 like나 substring을 사용해 추출해야 한다. 
    이는 인덱스 설정을 했다고 해도 인덱스를 타지 않을 수 있다.  또한 %를 사용하면 데이터를 거의 풀 스캔하기 때문에 효율성 부분에서도 떨어진다. 
  • 조인 대상 테이블이 되는 경우 해당 데이터를 추출하기가 복잡해진다.
  • 그리고 해당 중복 값을 조립하는 방식이 분해하는 방식보다 훨씬 간단하다. 
    문자열을 조립하는 방법 ||, concat 등.. 다양한 함수를 지원하기 때문에 조회 칼럼에 대해서 너무 걱정하지 않아도 된다.

 

하지만 데이터를 분리할 때 매우 신중을 가해야 한다. 애플리케이션의 요구 사항, 변경 예정 사항을 보고 어느 부분을 작게 분리할 것인지 검토하고 결정해야 한다. 

 

 

3. 계산된 데이터 저장

 

SQLD를 공부하면서 캐싱을 위해 계산된 칼럼을 별도로 구성해 사용하는 경우를 공부한 적이 있다. 

 

그런데 가끔 캐싱을 하지 않아도 될 것 같은데 계산 칼럼을 별도로 구성해 사용하는 경우가 있다. 

이러한 불필요한 계산 컬럼은 데이터베이스 성능에 매우 심각한 영향을 미칠 수 있다. 

 

개발자가 한 가지 작업을 의도했지만 내부적으로는 여러 번 연산이 일어나기 때문인데, 계산 칼럼과 관계가 있는 칼럼들의 update, insert, delete에 모두 반응을 해야 하기 때문이다. 

 

그럼 정답이 나왔다. 계산 칼럼을 사용함으로 얻는 이득이 부하를 일으키는 비용보다 클 때만 사용하면 된다. 

 

 

4. 참조 무결성 중요할까?

 

나는 중요하다고 생각한다. 

 

참조 무결성이 깨지게 되면 해당 애플리케이션은 반드시 오류가 발생한다.  분명 코드 단에서 데이터가 없으면 안 되는데 없는 경우가 있다.  왜 부모 키로 자식 테이블을 존재했는데 다른 자식이 튀어나오는 경우를 생각해보자. 

그 이후 다른 부모의 자식을 변경하거나 삭제한다?  이러한 작동이 한 번만 이뤄져도 복구에 들이는 비용은 어마무시할 것이다. 

이렇게 버그를 제약조건으로 잡을 수 있다면 나는 당연히 해야한다고 생각하는 주의이다. 

 

또 데이터베이스마다 다르지만 이러한 참조 무결성 제약 조건을 정의하면 자동으로 외래 키 칼럼에 인덱스를 만들어 주기도 하는데 이는 조인 수행 시 성능 향상 효과가 있을 수 있다. 만약 만들어 주지 않는다면 별도로 만들어 주어도 된다.

 

 

5. 정규화를 이해해야 하는가?

 

데이터베이스와 애플리케이션이 관계가 있다냐고 물었을 때 우리는 그렇다고 한다.

그러니까 정규화를 이해하고 위반하는 경우를 찾아 개선할 수 있어야 한다. 

 

일반적으로 정규화된 테이블은 비정규화된 테이블에 비해 칼럼의 개수도 적고 저장 공간도 작다. 

데이터가 적다는 것은 테이블이 작다는 말이기 때문에 성능이 좋아진다.  데이터 저장 시에도 별도의 공간에 할당되어있기 때문에 삽입, 갱신도 빠르고, 중복되지 않은 데이터가 보장되어 불필요한 그룹화나 DISTINCT가 줄어든다. 

 

다만 정규화 내용은 매우 어렵다. 몇번을 읽어도 3~6 정규화 단계는 이해하기 매우 힘들고 적용할 때 비즈니스를 고려하면서 정규화를 해야 하기 때문에 시간도 많이 쓰게 되는 것 같다. 

정규화라는 것이 결국 추가 테이블이 생성되는 것이기 때문에 테이블을 설계하고 관계 설정을 하고 개별 속성, 타입도 정해지고 나면 애플리케이션에서 코드로 그만큼 작업을 더해야 하긴 한다. 

 

 

만약 반정규화를 해야 한다면 그 이유는 타당해야 한다. 왜 중복을 허용해야 하는지, 중복으로 인한 단점보다 이점이 더 많은지, 데이터를 동기화할 방법은 무엇인지, 문서화 등등.. 

 

반 정규화는 의도가 숨어있다. 이를 잘 보여줄 수 있는 수단이 반드시 필요하다고 생각한다. 

 

 

 

 

 

 

오전에만 잠깐 이해하려고 했는데 벌써 오후가 되어버렸다..

데이터베이스는 쉬운 듯 하면서도 비즈니스와 엮어버리는 순간 매번 선택의 연속인 것 같다. 

조금이라도 좋은 설계를 가진 데이터베이스를 만들어나가는 것이 목표이기에

주말 중 한번 오전에 관련 지식을 습득 해나갈 생각이다.

 

 

 

반응형

'Database > SQL' 카테고리의 다른 글

SQL 코딩테스트 연습  (0) 2022.10.17
[유선생] SQL 개발자 (3)  (0) 2022.02.12
[유선생] SQL 개발자 (2)  (0) 2022.02.04
SQL 개발자  (2) 2022.01.23
Join 연산을 이용한 select문  (0) 2021.02.27

댓글