데이터과학 유망주의 매일 글쓰기 — 열한 번째 토요일

배우는 자(Learner Of Life)
11 min readNov 21, 2020

--

데이터베이스의 정규화(Database Normalization)

#데이터베이스 설계

책장도 하나의 데이터베이스다. 책장 속에 책을 어떻게 하면 효율적으로 배치할 수 있을까?

오늘 한일:

어제는 ACID라는 데이터베이스가 갖추어야할 가장 기본적인 4가지 요소에 대해서 알아보았다. 다시 리뷰하자면 모든 트렌젝션이 가장 작은 단위로 나뉘어져야 하며 모든 단위의 트렌젝션이 성공해야 전체가 성공한다는 원자성(Atomicity), 데이터베이스의 상태는 트랜잭션 이전과 이후에도 변화가 없어야 한다는 일관성(Consistency), 데이터베이스가 병렬로 트랜젝션을 하는 결과가 직렬로 했을 때와 같아야한다는 독립성(Isolation). 각 트랜젝션은 기록을 남겨야 한다는 지속성(Durability)로 나뉜다.

이렇게 중요한 ACID 개념이외에도, SQL기반 데이터베이스를 설계할 때 유의해야하는 추가적인 개념들이 더 있는데 그 중에 하나가 바로 데이터베이스 정규화(Normalization)라는 개념이다. 이 개념은 세부적으로 중복성(Redundancy), 무결성(Integrity), 마지막으로 이상 현상(Anomaly)으로 나뉘어진다. 데이터베이스의 정규화는 데이터베이스의 데이터를 최소화하는 것이 목적이다. 오늘 블로그에서는 데이터베이스의 정규화가 어떻게 이루어 지는지 알아보자.

데이터베이스의 정규화(Data Normalization)

데이터 중복성(Data Redundancy)

데이터베이스를 설계할 때 중복되는 데이터의 존재를 피하는 것이 좋다. 데이터베이스가 중복될 경우, 같은 칼럼에 같은 데이터가 여러개 존재할 수도 있고, 여러 다양한 이름을 가진 칼럼에 비슷한 정보들이 존재할 수 있다. 예를 들어, 온라인 쇼핑몰의 개인 거래 내역 처럼 개인이 얼마나 물건을 주문하더라도, 추후에 물건을 받지 못했거나 반품이 필요할 시에 그 내역이 온전히 다 필요한 경우가 있다. 이 경우 한 사람이 모든 시간 동안 어떠한 물품을 주문했는지 알아야하기 때문에, 각 물품들을 기준으로 같은 사람의 이름이 여러번 있을 수 있거나, 한 사람을 기준으로 같은 물품들이 여러번 있을 수 있다. 하지만 이와는 반대로 온라인 쇼핑몰 내부 직원의 명단을 활용할 경우, 중복된 데이터의 존재는 오히려 특정 직원의 정보를 파악하는데 방해가 될 수 있다. 이 때는 한 직원에 대해 일관된 데이터를 가져가기 어렵고, 저장 공간도 낭비되며, 따라서 데이터베이스의 효율성이 떨어지는 결과를 초래하게 된다.

데이터 무결성(Data Integrity)

데이터가 유효한 동안은, 정확하고 일관된 성질을 가져야한다. 이 개념은 ACID의 일관성(Consistency)의 개념과 어느정도 평행하다. ACID에서 “C”인 일관성은, “데이터베이스의 데이터 상태가 그 어떤 트랜젝션 이전과 이후에도 변함이 없어야한다.”라고 정의하고 있다. 사실 이는, 데이터 입장에서 “데이터베이스 안에서 무결성을 유지해야한다.”라는 의미로 해석될 수 있다. 데이터베이스에 입력된 데이터가 변형되지 않고, 원형 그대로 언제든지 사용될 수 있어야 한다는 의미다. 데이터가 데이터베이스안에 존재하는 동안은, 특별한 명령이 있지 않는한, 이미 존재하는 데이터 그대로의 상태를 변질시켜서는 안된다.

데이터 이상 현상(Anomaly)

데이터의 상태는 예측 가능해야 한다. 데이터의 이상 현상은 대표적으로 아래 세 가지로 구분된다.

  • 갱신 이상(Update Anomaly)
  • 삽입 이상(Insertion Anomaly)
  • 삭제 이상(Deletion Anomaly)

먼저 갱신 이상(Update Anomaly)란, 같은 데이터가 여러 레코드(행)에 입력되어 있는 경우, 그 중 어떤 데이터를 갱신해야 하는지에 대해 명확한 구분이 사라지는 현상을 말한다. 예를 들어 아래와 같이 북유럽 신화 4명의 캐릭터를 ID를 통해 구분하는데, 이중 2명의 캐릭터들이 중복되는 ID가 있다고하자.

북유럽 신화의 4명의 캐릭터 중 중복되는 ID를 가진 캐릭터들이 2명이 있다.

이러한 경우 “ID = 1” 로 캐릭터를 찾을 때, Odin을 갱신해야 하는지 아니면 Thor를 갱신해야 하는지에 대한 명확한 기준이 없는 상태가된다. 이 상황에서는 데이터베이스가 어떤 데이터를 건네주어야 하는지에 대해 예측할 수 없게 된다. 이러한 경우 데이터베이스가 첫 번째 데이터를 갱신하거나, 둘다 갱신하거나, 아니면 추가적으로 구분할 수 있는 칼럼 정보(Name = “Odin”, 또는 Name = “Thor” 등)를 입력하도록 에러 메시지를 띄우는 등, 좀 더 명확한 기준을 설계할 필요가 있다.

삽입 이상(Insertion Anomaly)

데이터의 삽입이 불가능한 현상이다. 예를 들어, 이전 북유럽 신화 데이터를 저장한 데이터베이스에서 반드시 모든 캐릭터가 아버지가 있어야한다는(“Father” 칼럼에 엔트리가 존재해야한다.) 규정이 생겼다고 가정하자. 4번 Ymir라는 캐릭터를 추가하고자 할 때, 이 캐릭터는 아버지(칼럼 “Father”의 정보)가 없기 때문에, 데이터를 추가 할 수 없는 이상 현상이 발생한다.

모든 캐릭터에 Father칼럼 정보가 있어야 한다는 규정이 있다면, 4번 “Ymir”의 데이터는 추가할 수 없게된다.

데이터베이스를 설계할 때는 의도치 않게 이러한 삽입 이상 현상이 생길 수 있다. 그러므로 삽입이 필요한 데이터가 부분적으로 데이터를 가지고 있지 않다면, 해당 데이터를 삽입 할 때 필요한 부분을 채워 넣을 수 있는지, 아니면 해당 데이터를 삽입하기 위해 데이터베이스의 규정을 수정할 수 있는지 생각해볼 필요가 있다. 만약 후자의 경우가 불가능 하다면, 충분한 데이터가 결정될 때까지 기다리거나, 전체 데이터의 삽입을 위해 임의로 만든 dummy 데이터를 넣어서 그 데이터가 아무 의미 없다는 정보를 같은 조직내에서 공유할 수 있어야 할 것이다. 사실 가장 좋은 해결책은, 처음부터 데이터베이스를 설계할 때 이러한 경우가 있을 수 있다는 사실을 고려하는 것이다.

삭제 이상(Deletion Anomaly)

데이터의 특정한 부분을 제거할 때, 의도하지 않았던 다른 부분이 동시에 제거되는 문제를 말한다. 만약 위 북유럽 신화 테이블에서, 데이터베이스의 유저가 Father칼럼의 “Ymir”, “Odin”, “Loki” 엔트리가 반드시 하나씩 존재하는 것을 원한다고 가정하자. ID = 2번을 지우게 된다면 Hel이라는 캐릭터는 물론이고, Loki라는 그녀의 아버지 정보도 같이 사라진다. 결과적으로, Hel이라는 캐릭터의 정보가 사라지는 것은 괜찮지만, Loki라는 캐릭터의 정보도 사라진다. 유저의 입장에서는 원하지 않는 정보가 같이 삭제 된 것이다.

3번 엔트리가 사라지면 데이터베이스는 더 이상 Loki라는 캐릭터의 정보를 가질 수 없다.

이러한 경우를 막기 위해서는 데이터를 삭제하려할 때, 해당 데이터가 삭제될 시에 같이 삭제될 데이터가 삭제되어도 무관한지를 확인할 필요가 있다. 만약 삭제되어서는 안된다면, 그 데이터 전체가 삭제되는 것을 막도록 데이터베이스의 규정을 설계할 필요가 있다. 예를 들어, 위 테이블에서는 2번의 “Hel”캐릭터의 정보가 삭제되면 Father칼럼의 “Loki”가 삭제되기 때문에, 삭제를 하지 못하게 하는 규정을 만들 수 있을 것이다.

가장 널리 쓰이는 데이터베이스와 그에 따른 기본적인 데이터 관련 규정

각 데이터베이스의 타입에 따라 어떤 데이터를 삽입할 수 있는지에 대해 나름의 기본적인 규정이 있는데 보통 아래와 같다. 흥미로운 것은 NoSQL기반 데이터베이스인 MongoDB 역시 “Dictionary의 리스트(JSON/BSON형태)”로 데이터를 입력해야 한다는 나름의 규정이 있다는 것이다.

  • MongoDB: Dictionary의 리스트 (JSON/BSON)형태로 입력
  • Postgres: execute_values - 데이터 타입이 유효하다면 상관없다. (특정 칼럼에 유효한 데이터 타입을 입력해야한다.)
  • OOP 메소드: 데이터 파이프라인 구축을 위해 Class를 생성해야한다.
  • SQLAlchemy Package: ORM(Object-Relational Mapping)을 생성한다.
  • Pandas: “DataFrame.to_sql” 함수를 사용하여 데이터를 SQL에 맞게 변환하여 삽입한다.

앞으로 할일:

오늘은 데이터베이스의 정규화에 대해 알아보았다. ACID만큼 데이터베이스를 설계할 때 유의하면 정말 좋은 가이드라고 할 수 있다. 여기에 있는 모든 규정은 어디까지나 권장사항으로써, 조직에 맞는 데이터베이스 설계법은 조금씩 다를 수 있다. 하지만, 일반적으로 대부분의 데이터베이스가 위 3가지의 정규화 가이드에 따라 설계된다면, 오랜 기간 동안 상당히 효율적으로 활용될 수 있다.

정규화라고하니, 지난 섹션에서 데이터의 표준화(Scaling, Normalizing, Standardizing)이 생각났다. 대표적으로 기억나는게 PCA라는 기법인데, 높은 차원(cardinality)를 가진 데이터의 분산을 유지하면서 작은 차원으로 줄이는 기법이다. 이 기법은 머신 러닝에서 모델링을 하기 전에 많은 경우 적용되는데, 크게 의미가 없는 불필요한 데이터를 줄일수록 모델의 성능이 더 좋아지는 경우가 있기 때문이다. 물론 개념은 조금 다르지만, 데이터베이스의 정규화도 마찬가지로, 데이터베이스의 효율성을 높이기 위한 작업이라는 생각이 들었다.

과정을 진행하면서 느끼는 것은 모든 지식과 개념들 사이에 분명한 연결고리가 존재한다는 것이다. 이번 주 내내 배운 관계형 데이터베이스의 특징은, 하나의 데이터베이스에 존재하는 서로 다른 테이블들 사이의 관계를 정의할 수 있다는 것이었다. 마찬가지로 내가 지금까지 배운 각 무수한 개념 안에서도 세부적으로 작은 개념들이 있는데, 서로 다른 전체 개념 사이에 존재하는 그 각각의 단위 개념들 사이에도 분명히 관계가 존재한다. 그 관계는 하나의 전체 개념의 하나의 단위 개념에서 다른 전체 개념의 하나의 단위 개념에 이어질 수 있다. 또는, 하나의 전체 개념의 하나의 단위 개념에서, 다른 전체 개념의 여러 단위 개념에 이어질 수도 있다. 또는, 하나의 전체 개념의 여러 단위 개념에서, 다른 전체 개념의 여러 단위 개념에 이어지기도 한다. 마지막으로, 하나의 전체 개념안에서, 각 단위 개념끼리의 관계가 존재할 수도 있다. 이렇듯, 내가 배운 모든 지식들도 서로 “일대일(1:1)", “일대다(1:N)", “다대다(N:N)" 관련이 있거나, 아니면 하나의 지식안에서 여러 세부지식들이 서로 관계가 있는 “자가참조(Self-Referencing)” 관계도 있다.

이번 주는 지금까지의 과정 중 가장 큰 산을 하나 넘긴 기분이다. 다음 주는 이번 주 보다는 조금 더 나았으면 좋겠다. 그러나 다음 주도 만만치 않은 경사가 기다리고 있다 한들, 지금까지 3분의 1의 여정을 마쳐온 나와 나의 동료들에게는 큰 문제가 될거라 생각하지 않는다. 기적같은 3달을 이겨낸 우리에게는 충분히 남은 여정도 견뎌낼 힘이 있으니까. 이제 어려움과 도전에 대해 나름의 내성이 생긴 느낌이다. 그 어떤 문제를 마주쳐도 당황해하기 보다는, “그래 컴퓨터 네가 그럴 줄 알았지” 라고 생각할 수 있을 것 같다. 컴퓨터가 우리 예상대로만 움직이는 경우보다, 그렇지 않는 경우가 더 많다는 것을 코딩을 조금이라도 해본 사람은 잘 알고있다. 그것에 익숙해져야한다. 그리고 다행이도 익숙해진 것 같다.

삶 역시 예상치 못한 에러를 마주함의 연속이다. 하지만 모든 에러가 다 그렇듯이, 반드시 수정하고 디버깅할 단서는 존재한다. 그리고 StackOverflow처럼 우리의 문제를 겪어본 선인들과 현인들이 반드시 무언가 우리가 맞이 할 모든 문제들에 대해 감사하게도 기록을 남겨놓았다. 삶에서도 예상치 못한 에러를 마주하면, 소크라테스, 공자, 빅터 휴고등 위대한 이들이 남긴 기록을 통해 우리가 무엇을 해야하는지 어느 정도 답을 얻을 수 있다.

한편으로는 이러한 시대에 태어난 것에 감사하다. StackOverflow 및 구글 같은 도구를 통해, 그 누구도 거의 대부분 자신의 문제에 대한 답이나 단서를 찾을 수 있다. 10여년 전만해도 그러한 커뮤니티를 상상조차 할 수 없었고, C계열의 언어는 인간의 언어와는 매우 동떨어져 있어, 프로그래밍은 소수의 특권으로 여겨졌다. 하지만 파이썬 같은 인간의 언어를 닮은 언어들이 생겨나고 검색만 하면 모든 에러에 대한 단서를 얻을 수 있는 사이트들이 생겨나면서, 프로그래밍은 훨씬 더 많은 부류의 사람에게 다가왔다. 그 어느 때 보다도 지식이 넘쳐나지만, 그 어느 때 보다도 그 어떤 지식에 접근하기가 용이한 세상이다. 원하는 것을 의지만 있으면 쉽게 방법을 찾아서 배울 수 있음에 감사하다.

힘들었던 만큼 어려움에 대한 내성도 생기고 근육도 생겼다. 지난 한 주 동안 새벽 2~3시까지 고생을 하면서 결국 과제를 완수했다. 이제는 그 어떤 것을 배우더라도 최선을 다해 결국해낼 수 있을 것만 같은 자신감이든다. 이 자신감을 다음 주도 계속 이어나갈 수 있기를.

--

--

배우는 자(Learner Of Life)
배우는 자(Learner Of Life)

Written by 배우는 자(Learner Of Life)

배움은 죽을 때까지 끝이 없다. 어쩌면 그게 우리가 살아있다는 증거일지도 모른다. 배움을 멈추는 순간, 혹은 배움의 기회가 더 이상 존재하지 않는 순간, 우리의 삶은 어쩌면 거기서 끝나는 것은 아닐까? 나는 배운다 그러므로 나는 존재한다. 배울 수 있음에, 그래서 살아 있음에 감사한다.

No responses yet