데이터베이스는 데이터를 체계적으로 저장하고, 여러 애플리케이션이 그 데이터에 안전하게 접근할 수 있게 해주는 시스템이다. 단순히 파일에 데이터를 저장하는 것과 다른 점은 일관성, 무결성, 동시성, 복구 같은 문제를 함께 다룬다는 데 있다.

서비스가 작을 때는 데이터를 저장하고 조회하는 것만으로 충분해 보인다. 하지만 사용자가 늘고, 여러 요청이 동시에 들어오고, 장애 상황에서도 데이터가 깨지면 안 되는 시점이 오면 데이터베이스가 제공하는 규칙과 보장이 중요해진다.

무결성과 키

데이터베이스에서 무결성은 데이터가 올바른 상태를 유지하도록 보장하는 성질이다. 예를 들어 회원 테이블의 기본 키가 중복되면 안 되고, 주문 테이블의 user_id가 존재하지 않는 회원을 가리키면 안 된다. 이런 규칙을 애플리케이션 코드에서만 관리하면 놓치기 쉽기 때문에 데이터베이스 차원에서도 제약을 둔다.

기본 키(Primary Key)는 각 레코드를 유일하게 식별하는 값이다. 외래 키(Foreign Key)는 다른 테이블의 기본 키를 참조해서 테이블 간 관계를 만든다. 후보 키는 기본 키가 될 수 있는 속성들이고, 그중 실제 기본 키로 선택되지 않은 키는 대체 키가 된다.

무결성 제약은 여러 형태로 나타난다. 기본 키가 NULL이 될 수 없다는 개체 무결성, 외래 키가 참조 대상과 맞아야 한다는 참조 무결성, 특정 컬럼이 허용된 값만 가져야 한다는 도메인 무결성 등이 대표적이다. 결국 목적은 데이터가 “말이 되는 상태”를 벗어나지 않게 하는 것이다.

인덱스는 조회를 빠르게 하지만 공짜는 아니다

인덱스는 데이터를 빠르게 찾기 위한 보조 구조다. 책에서 원하는 내용을 찾을 때 목차나 색인을 보는 것과 비슷하다. 조건절에 자주 등장하고, 값의 종류가 충분히 다양한 컬럼에 인덱스를 걸면 조회 성능이 좋아질 수 있다.

하지만 인덱스는 공짜가 아니다. 데이터를 삽입하거나 수정하거나 삭제할 때 인덱스도 함께 갱신해야 한다. 인덱스가 너무 많으면 조회는 빨라질 수 있어도 쓰기 성능이 떨어지고 저장 공간도 더 사용한다. 그래서 인덱스는 “자주 조회되는가”, “카디널리티가 높은가”, “정렬이나 조인에 활용되는가”를 보고 신중하게 추가해야 한다.

관계형 데이터베이스에서 가장 흔한 인덱스 구조는 B-Tree 계열이다. 범위 검색과 정렬에 유리하고, 균형 잡힌 트리 구조라 검색 비용이 안정적이다. 해시 인덱스는 등치 검색에는 빠를 수 있지만 범위 검색에는 적합하지 않다. 텍스트 검색처럼 복잡한 조건에는 GIN이나 FULLTEXT 같은 별도의 인덱스 구조를 사용하기도 한다.

RDBMS와 NoSQL

관계형 데이터베이스(RDBMS)는 정해진 스키마와 테이블 간 관계를 기반으로 데이터를 관리한다. 데이터의 정확성과 일관성이 중요한 시스템에 잘 맞는다. 은행, 주문, 결제, ERP처럼 데이터가 틀어졌을 때 비용이 큰 영역에서는 RDBMS의 장점이 크다.

NoSQL은 더 유연한 스키마와 수평 확장을 중시하는 경우에 선택된다. 로그, 이벤트, 소셜 피드, 대규모 비정형 데이터처럼 데이터 형태가 자주 바뀌거나 쓰기 규모가 큰 경우에 유리할 수 있다. 다만 모든 NoSQL이 일관성을 포기한다는 뜻은 아니고, 제품마다 보장 수준과 사용 방식이 다르다.

선택 기준은 단순히 “RDBMS는 안정적이고 NoSQL은 빠르다”가 아니다. 데이터 모델이 얼마나 명확한지, 트랜잭션이 얼마나 중요한지, 수평 확장이 필요한지, 조회 패턴이 어떤지에 따라 달라진다.

트랜잭션과 ACID

트랜잭션은 여러 데이터 변경을 하나의 논리적인 작업 단위로 묶는 개념이다. 계좌 이체를 예로 들면 A 계좌에서 돈을 빼고 B 계좌에 돈을 넣는 두 작업이 모두 성공해야 한다. 중간에 하나만 성공하면 데이터가 깨진다. 그래서 실패하면 전체를 롤백하고, 성공하면 전체를 커밋한다.

ACID는 트랜잭션이 지켜야 할 성질을 설명한다. 원자성은 전부 성공하거나 전부 실패해야 한다는 뜻이다. 일관성은 트랜잭션 전후로 데이터베이스가 유효한 상태를 유지해야 한다는 뜻이다. 격리성은 동시에 실행되는 트랜잭션이 서로 어긋나지 않게 보이도록 하는 성질이고, 지속성은 커밋된 결과가 장애 이후에도 남아 있어야 한다는 뜻이다.

전자상거래에서도 같은 문제가 생긴다. 주문 생성, 재고 감소, 결제 기록 저장이 따로 놀면 안 된다. 하나라도 실패하면 전체 주문을 취소해야 한다. 이런 상황에서 트랜잭션은 서비스의 데이터 정합성을 지키는 기본 장치가 된다.

CAP과 PACELC

분산 데이터베이스를 다룰 때는 CAP 이론도 자주 등장한다. CAP은 일관성(Consistency), 가용성(Availability), 분할 내성(Partition Tolerance)을 말한다. 네트워크 분할이 발생한 상황에서는 모든 노드가 같은 데이터를 보게 할 것인지, 일부 불일치가 있더라도 응답을 계속할 것인지 선택해야 한다.

PACELC는 이 관점을 조금 더 확장한다. 장애가 있을 때는 일관성과 가용성 사이에서 선택해야 하고, 장애가 없을 때도 지연 시간과 일관성 사이의 균형을 선택해야 한다는 설명이다. 즉 분산 시스템의 데이터베이스 선택은 장애 상황뿐 아니라 평상시 응답 속도와 일관성 요구까지 함께 고려해야 한다.

데이터베이스를 공부할 때는 용어를 외우는 것보다 각 개념이 어떤 문제를 해결하기 위해 나왔는지 보는 편이 좋다. 키와 무결성은 데이터가 말이 되게 만들고, 인덱스는 조회 비용을 줄이고, 트랜잭션은 여러 변경을 안전하게 묶고, CAP/PACELC는 분산 환경에서 무엇을 포기할지 판단하게 해준다.