오늘
우리가 사용하는 대부분의 서비스들에는 데이터베이스가 존재합니다. 유튜브의 영상 목록, 학교 수강 신청 시스템까지 실제 데이터가 오고 가는 지점이 있고, 우리가 화면에서 보는 것은 단순한 UI일 뿐입니다. 그 뒤에서는 방대한 데이터를 다루는 데이터베이스가 핵심 역할을 맡고 있습니다. 단순히 데이터를 저장하기 위해서라면 파일로도 충분해 보일 수 있지만, 수많은 사용자가 동시 접근, 일관성 유지 등 시스템 안정성과 성능과 직결되는 문제가 발생할 수 있습니다. 데이터를 잘 다루기 위해, 데이터를 어떻게 저장하고 사용할 수 있는지 그 시스템에 대해 글을 써보려고 합니다.
조화된 정보 또는 데이터의 조직화된 모음. 단순히 파일에 데이터를 저장하는 것과 달리, 데이터베이스는 관리 시스템에 의해 데이터 중복을 최소화하고, 일관성, 무결성, 보안성을 보장하면서 효율적인 검색과 갱신을 가능하게 합니다. 이렇게 연결된 애플리케이션과 함께 데이터와 DBMS를 하나로 묶어 데이터베이스 시스템이라고 하며 단축하여 데이터베이스라고도 합니다. 사용방식에 따라 유형을 나눌 수 있습니다. 관계형 데이터베이스, 객체 지향 데이터베이스, 그래프 데이터베이스, NoSQL 데이터베이스, 자율 운영 데이터베이스 등 정말 많은 유형이 존재합니다. 오늘은 그 중에서도 1980년부터 대부분 서비스에서 채택되었으며 DB 기본 개념을 익히기 쉬운 관계형 데이터베이스를 기준으로 다뤄보려고 합니다.
DB 강의, 기타 자격증에서는 대부분 관계형 데이터베이스를 다룹니다. 이는 엄격한 구조와, 제약 조건을 보장하기 때문인 것 같습니다. 특히 명확한 구조와 ACID 트랜잭션 등의 특징으로 학습에 용이합니다. 그러나 이런 강력한 시스템이 필요하지 않은 서비스의 경우 확장성과 속도를 중시하여 NoSQL DB를 선호한다고도 합니다. SQL, 고급 쿼리 기능이 필요하지 않은 경우인 것 같습니다. 조금 더 상위 레벨의 개발자가 된다면 데이터베이스 모델링의 유형을 다양하게 파악하여 선택할 수 있도록 학습해야겠습니다.
위에서 이야기했던 애플리케이션, 데이터베이스를 관리하는 소프트웨어를 의미합니다. 데이터베이스와 최종 사용자 또는 프로그램 간의 인터페이스 역할을 하여 사용자가 정보의 구성 및 최적화 방법을 검색, 업데이트 및 관리할 수 있게 해줍니다. 또한 DBMS는 데이터베이스의 감독 및 제어가 용이하여 성능 모니터링, 튜닝, 백업, 복구 같은 다양한 관리 작업이 가능합니다. 즉, 사용자와 데이터베이스 사이에서 중간 계층 역할을 하며, 데이터에 대한 접근을 체계적으로 제어하는 역할입니다. 관계형 데이터베이스에서(RDBMS) 가장 많이 언급 되는 것은 주로 MySQL, PostgreSQL, MariaDB 정도가 있습니다.
File System과 DB를 비교할 때 등장하는 개념인데, File System이 보장하지 못하는 것들(동시 접근, 무결성 보장, 원자성) 등을 보장할 수 있는, 즉 DB가 보장하는 기존 File System의 대한 Solution을 제공한다고 이해했습니다.
구체적으로 데이터베이스의 구조에 대해 살펴보겠습니다. 데이터베이스의 구조와 제약조건을 스키마로 표현합니다. 즉 일종의 설계도입니다. 데이터베이스 생성 시에 주로 결정하며, 자주 변경하면 안 됩니다. 크게 3가지로 나눌 수 있습니다.
외부 스키마(External Schema): 각 사용자나 응용 프로그램이 보는 데이터베이스의 뷰(View). 사용자마다 다른 관점을 제공한다 -> 어떤 사용자가 어떤 데이터베이스, 테이블에 접근할 수 있는지
개념 스키마(Conceptual Schema): 데이터베이스 전체의 논리적 구조를 정의한다. 모든 사용자가 공유하는 통합된 관점이다 -> 모든 테이블의 관계와 속성, 제약 조건 등 정의(외부 스키마만 정의하면 무결성 문제가 발생할 수 있음)
내부 스키마(Internal Schema): 데이터가 물리적으로 저장되는 방식을 정의한다. 인덱스 구조, 저장 레코드 형식 등이 포함된다.
아래는 예시입니다.

이 때 하나의 스키마가 변경되어도 다른 스키마가 변경되지 않도록 설계합니다(이를 데이터 독립성이라고 합니다)
위의 스키마를 바탕으로 시각적으로 모델링하는 방법이 있습니다. 이 때 주로 사용하는게 ER-Diagram(Entity Relationship Diagram)입니다. 개체(Entity)와 개체 간의 관계(Relationship)를 도식화한 것으로, ERD를 구성하는 핵심 요소는 다음과 같습니다. 예시로 학생과 수강의 관계를 사용해봤습니다.
개체(Entity): 현실 세계에서 독립적으로 존재하는 사물이나 개념. (예: 학생, 강좌)
속성(Attribute): 개체의 특성이나 성질. (예: 학번, 이름)
관계(Relationship): 개체 간의 연관성. (예: 학생이 강좌를 수강하다)
카디널리티(Cardinality): 두 개체 간의 대응 관계. 1:1, 1:N, M:N으로 표현한다. (예: 한 학생은 강좌를 여러 개 수강할 수 있고, 한 강좌도 여러 학생이 듣는다. 즉 M:N 관계이다)
다음은 ERD의 예시를 하나 가져와 보았습니다.

위 방법은 Crow's foot 방식으로 그려져 있습니다. PK, FK는 뒤 내용에서 다루기로 하고, 중요한 것은 엔티티 안에서 속성 들이 정의되어 있고, 관계도가 그려진다는 것입니다(이 요소를 마름모, 타원 등 도형으로 보여주는 방식도 쉽게 찾아볼 수 있을텐데 Peter Chen 방식이라고 합니다).
조사하면서 테이블에서 사용하는 카디널리티와 헷갈렸는데 릴레이션 내부에서 사용하는 카디널리티는 튜플의 수, 전체 데이터베이스 모델링에서는 엔티티 간의 관계를 나타낼 때 쓰는 용어로 구분해서 쓰면 될 것 같습니다.
이제 실제로 우리가 볼 데이터베이스의 테이블을 기준으로 요소들을 살펴봅시다. 아래 테이블 예시와 함께 용어를 정리해보겠습니다.

위의 테이블은 학생들의 정보를 저장해놓은 테이블(릴레이션)입니다. 이 테이블에서 다음과 같은 정보를 확인할 수 있습니다.
튜플(Tuple): 릴레이션의 각 행(Row)을 가리키며, 하나의 레코드(Record)에 해당한다. 한 개체에 대한 속성 값들의 모음이다. 순서에는 의미가 없으며, 모든 내용이 겹치면 안 됩니다(중복 금지). ex, 첫 번째 튜플은 2023001/김민수/컴퓨터공학
애트리뷰트(Attribute): 릴레이션의 각 열(Column)을 가리키며, 개체의 특성을 나타낸다. ex, 이 테이블에서는 학번, 이름, 전공 이라는 애트리뷰트가 있습니다.
추가로 알아두면 유용한 개념들도 정리하면
도메인(Domain): 각 애트리뷰트가 가질 수 있는 원자 값들의 집합이다. ex, 전공 애트리뷰트의 도메인은 {컴퓨터공학, 경영학, 수학 ~~~}입니다.
차수(Degree): 릴레이션이 가진 애트리뷰트의 수. ex, 여기서는 3
카디널리티(Cardinality): 릴레이션이 가진 튜플의 수. ex, 여기서는 3
위의 개념을 정리해두면 추후 데이터베이스의 제약 조건, 정규화 등을 설명할 때 유용합니다.
위의 ERD를 살펴보면 각 엔티티가 연결되어 있습니다. 이 때 학생이 수강과목과 관계를 가지고 있는데, 그렇다면 한 학생이 수강하고 있는 과목에 대해서 어떻게 조회할 수 있을까요. 또 동명이인이 있을 경우 어떻게 구분할 수 있을까요. 이런 의문을 해결해주는 것이 Key입니다. 쉽게 말하면 하나의 엔티티(릴레이션)이 가지는 속성들 중 특정한 역할을 할 수 있는 속성들이죠. 그 중에서도 필수적인 기본키와 외래키를 정리해보겠습니다.
Primary key: 릴레이션 내의 각 튜플을 유일하게 식별할 수 있는 애트리뷰트 또는 애트리뷰트의 집합입니다. 학생 테이블에서는 학번이 될 수 있습니다. 기본키가 될 수 있는 조건은 두 가지 입니다. 유일성과 최소성. 유일성은 릴레이션 내에서 중복된 값을 가지지 않는 것, 최소성은 하나라도 제거하면 유일성이 깨지는, 즉 최소한의 속성만으로 구성되어야 한다는 것이죠(최소성 때문에 학번 + 이름은 기본키가 되지 않습니다). 기본키는 Null을 허용하지 않으며, 이를 개체 무결성 제약이라고 합니다.
Foreign Key: 릴레이션의 애트리뷰트가 다른 릴레이션의 기본키를 참조할 때, 그 애트리뷰트를 말합니다. 위의 사례에서 수강과목 릴레이션이 학번을 외래키로 하여 학생 정보를 조회한다고 생각하면 됩니다. 즉 두 릴레이션 간의 관계를 맺어주는 속성이 됩니다. 이 때 외래키는 반드시 참조하는 릴레이션에 존재하는 기본키 값이거나, NULL이어야 한다는 규칙이 있습니다. 이를 참조 무결성 제약이라고 하며, 존재하지 않는 데이터 참조하는 문제를 방지할 수 있습니다.
자 그렇다면 데이터베이스에 이렇게 저장되는 데이터들을 어떻게 꺼내고, 사용할까요. 바로 SQL(Structured Query Language)을 사용합니다. 관계형 데이터베이스에서 데이터를 정의하고 조작하기 위한 표준 언어로, 3가지 유형으로 나눌 수 있습니다.
DDL (Data Definition Language): 테이블이나 스키마 등 데이터 구조를 정의한다. CREATE, ALTER, DROP 등이 해당한다.
DML (Data Manipulation Language): 데이터를 조회하고 변경한다. SELECT, INSERT, UPDATE, DELETE 등이 해당한다.
DCL (Data Control Language): 사용자 권한을 제어한다. GRANT, REVOKE 등이 해당한다.
또 가장 많이 사용하는 SELECT문을 통해 구조를 살펴보면
SELECT 컬럼명
FROM 테이블명
WHERE 조건
GROUP BY 그룹 기준 컬럼
HAVING 그룹 조건
ORDER BY 정렬 기준 컬럼;이렇게 구성할 수 있습니다. 문법마다 구조가 다르니 확인해야하며, 해석되는 순서도 다릅니다(그러나 의미를 생각하면서 사용하면 대게 문제는 없다). 외에도 테이블과 테이블을 연결해서 사용할 수 있는 JOIN 문법도 존재하는데, 어느 테이블을 base로 사용할지에 따라 outer join, inner join으로 나눌 수 있습니다.
쿼리는 '질의' 또는 '요청'을 의미하는데, 데이터베이스에 SQL이라는 언어로 요청을 하는 것이 때문에 SQL 쿼리로 부른다고 생각하면 될 것 같다.
위에서 해결되지 않은(엄격하게 제한하지 않은 문제들)이 있습니다. 여기서 등장하는 게 정규화 입니다. 정규화(Normalization)란 데이터베이스 설계 시 데이터 중복을 최소화하고 이상 현상(Anomaly)을 방지하기 위해 릴레이션을 체계적으로 분해하는 과정입니다. 이상 현상에는 삽입 이상, 삭제 이상, 수정 이상이 있고, 각 단계별로 문제를 해결해나갑니다.
제1 정규형 (1NF) 릴레이션의 모든 도메인이 원자 값(Atomic Value)만으로 구성되어야 한다. 즉, 하나의 셀에 여러 값이 들어가거나 반복 그룹이 존재해서는 안 됩니다. ex, 전화번호 속성에 인터넷 전화, 휴대폰 번호 두 개가 저장된 경우
제2 정규형 (2NF) 1NF를 만족하면서, 모든 Non-key 애트리뷰트가 기본키 전체에 완전 함수 종속(Full Functional Dependency)되어야 한다. 기본키의 일부에만 종속되는 부분 함수 종속(Partial Dependency)을 제거해야 한다. 기본키가 단일 애트리뷰트인 경우 자동으로 2NF를 만족한다. ex, 기본키를 주민번호 + 이름으로 하였을 경우, 주민번호만으로도 함수 종속이 발생한다(기본키 전제가 잘못되긴 했으나, 예시가 생각이 안나네요 ㅎㅎ...)
제3 정규형 (3NF) 2NF를 만족하면서, Non-key 애트리뷰트 간의 이행 함수 종속(Transitive Dependency)이 존재해서는 안 된다. 즉, A → B이고 B → C인 경우 A → C가 되는 이행 종속을 제거해야 한다. 이를 위해 이행 종속이 발생하는 애트리뷰트를 별도 테이블로 분리한다. ex, 쇼핑몰에서 등급에 따라 할인율이 결정되는 경우, 그 회원의 기본키가 할인율을 결정할 수 있다. 즉 등급 -> 할인율, 회원ID -> 할인율이 되므로 이행 종속
BCNF (Boyce-Codd Normal Form) 3NF보다 조금 더 엄격한 정규형으로, 모든 결정자(Determinant)가 후보키(Candidate Key)여야 한다. 3NF를 만족하더라도 하나의 릴레이션에 여러 후보키가 존재하고 그 후보키들이 서로 복합적으로 구성될 때 이상 현상이 발생할 수 있으며, BCNF는 이를 해결한다. ex, 결정자라는 것은 이 속성으로 인해 다른 값을 결정할 수 있는 경우를 이야기 합니다. 예를 들어 수강 정보(학번, 과목명, 교수)가 있을 때 교수명 만으로 과목을 알 수 있을때(학번+과목명이 기본키) 교수명으로 과목을 알 수 있다. 다만 학번을 알 수는 없으므로 후보키로 쓸 수 없다. 이를 제거하는 것이 BCNF이다.
위의 소개된 이상 현상을 방지해야 하는 이유는 대부분 중복 행 저장, 수정/삭제 시 모든 데이터를 수정하지 않았을 때 에러가 발생하는 경우를 막기 위해서 입니다.
4정규화, 5정규화도 있습니다. 다만 더 복잡한 종속 관계를 고려할 수록 테이블을 과도하게 많이 나누게 됩니다. 따라서 보통 BCNF까지 고려하고, 4정규화, 5정규화는 관련된 이상 현상이 발생할 수 있을 경우 사용한다고 합니다. 실제 데이터베이스 설계 시에 마스터 테이블이라고 하는 정규화와 상반되는 사용법이 있기도 하고, 데이터 시각화나 사용에 있어서도 정규화를 따르는 게 반드시 정답은 아니라고 합니다.
오늘은 데이터베이스 기본 내용들을 다뤄보았습니다. 사실 대부분 학부 강의나 자격증 공부를 하며 정리했던 내용이라 복습에 가까웠습니다. 다만 실제로 데이터베이스를 서비스 차원에서 구축해보는 실습은 해본 적이 없어서 이번 세션이 기대됩니다(항상 데이터베이스 개념을 눈으로 보고, 쿼리 연습을 위해서만 사용해봄). 요즘 빅데이터산업기사부터 해서 관련 자격증이 많은 것으로 아는데 한 번 공부해두면 범위가 모두 겹치니 정리해두면 좋을 것 같습니다.
참고: https://www.oracle.com/kr/database/what-is-database/ (오라클)
https://eunjin123123-programming.tistory.com/110 테이블 사진
https://velog.io/@tkdgus5828/DB-%EC%8A%A4%ED%84%B0%EB%94%94-1-DB-DBMS-Schema 스키마 사진
댓글 0