실제 데이터베이스는 내부적으로 어떻게 작동하나요?
Source: Dev.to
위의 링크에 있는 전체 글을 번역하려면, 번역하고 싶은 텍스트(마크다운 형식 포함)를 그대로 복사해서 여기 채팅창에 붙여 주세요.
그럼 요청하신 대로 소스 링크는 그대로 두고, 내용만 한국어로 번역해 드리겠습니다.
실제 데이터베이스가 아닌 것
- 메모리 내의 거대한 테이블
- CSV 파일들의 모음
- 단순한 키‑값 맵
핵심 구성 요소
정교한 데이터베이스는 여러 긴밀하게 통합된 하위 시스템으로 구성됩니다:
- Parser
- Planner / Optimizer
- Execution Engine
- Storage Engine
- Buffer Cache
- Transaction Manager
- Recovery System
Source: …
쿼리 처리 파이프라인
문장을 실행할 때, 예를 들어:
SELECT name FROM users WHERE age > 30;
데이터베이스는 즉시 테이블을 스캔하지 않습니다. 대신 다음과 같은 엄격한 파이프라인을 따릅니다:
구문 분석 및 검증
- SQL 텍스트를 추상 구문 트리 (AST) 로 변환합니다.
- 다음을 확인합니다:
- 구문이 올바른지 여부
- 테이블 및 컬럼 이름이 유효한지 여부
- 사용자 권한
이 단계에서는 데이터를 전혀 접근하지 않습니다.
최적화
쿼리 옵티마이저는 다음을 결정합니다:
- 사용할 인덱스
- 조인 순서
- 스캔 방식 (인덱스 스캔 vs. 순차 스캔)
- 통계에 기반한 비용 추정
전형적인 판단 예시:
- 100만 행을 순차적으로 스캔하는 것이 더 저렴한가?
- 아니면 무작위 I/O가 발생하는 인덱스를 사용하는 것이 나은가?
현대 데이터베이스는 다음을 활용합니다:
- 비용 기반 옵티마이저
- 통계 (히스토그램, 카디널리티)
- 규칙 기반 재작성
이 단계가 하드웨어보다 성능에 더 큰 영향을 미치는 경우가 많습니다.
실행
옵티마이저는 실행 계획을 생성합니다. 실행 엔진은 이후:
- 연산자들을 통해 행을 끌어옵니다 (스캔 → 필터 → 프로젝션)
- 이터레이터 또는 벡터화 실행을 사용합니다
- 모든 데이터를 메모리에 로드하지 않고 스트리밍 방식으로 결과를 반환합니다
핵심 개념: 데이터베이스는 데이터를 한 번에 모두 처리하는 것이 아니라 파이프라인 방식으로 처리합니다.
스토리지 레이아웃
페이지
Data is stored in fixed‑size pages (commonly 4 KB–16 KB).
각 페이지는 다음을 포함합니다:
- 페이지 헤더
- 행 슬롯
- 메타데이터
Pages are the minimum unit of I/O.
페이지는 I/O의 최소 단위입니다.
행 지향 vs. 열 지향 스토어
| 스토어 유형 | 일반적인 사용 | 특징 |
|---|---|---|
| 행 지향 (PostgreSQL, MySQL) | OLTP | 빠른 삽입 및 포인트 쿼리 |
| 열 지향 (ClickHouse, Redshift) | Analytics | 뛰어난 압축 및 벡터화 스캔 |
인덱스
Indexes are separate data structures, most commonly:
- B‑Trees – 데이터를 정렬된 상태로 유지하고, 디스크 탐색을 최소화하며, 읽기/쓰기 비용을 균형 있게 합니다
- Hash 인덱스
- LSM Trees (RocksDB, Cassandra)
중요한 사실: 인덱스는 읽기 속도를 높이지만 쓰기 속도를 늦춥니다. 이는 모든 삽입/업데이트가 테이블 데이터와 모든 관련 인덱스를 모두 수정해야 하기 때문입니다.
버퍼 캐시와 내구성
데이터베이스는 메모리만을 신뢰하지 않는다. 자주 사용되는 페이지는 RAM에 캐시되며, 더티 페이지는 교체 전략(LRU 변형)을 사용해 나중에 다시 디스크에 기록된다.
전원이 끊기면 메모리는 사라지므로, 디스크는 일관성을 유지해야 한다.
ACID 보장
실제 데이터베이스는 Atomicity, Consistency, Isolation, Durability를 **Write‑Ahead Log (WAL)**을 통해 보장합니다:
- 데이터를 수정하기 전에 변경 사항을 로그에 기록합니다.
- 로그를 디스크에 플러시합니다.
- 그 후에 메모리 페이지를 업데이트합니다.
데이터베이스가 충돌하면 WAL을 재생하여 데이터를 복구합니다. 로그는 종종 데이터 파일보다 더 중요합니다.
동시성 제어
데이터베이스는 다음을 사용하여 수천 명의 동시 사용자를 지원합니다:
- 잠금(행, 페이지, 테이블)
- MVCC (다중 버전 동시성 제어)
MVCC에서는:
- 읽는 작업은 쓰는 작업을 차단하지 않습니다.
- 쓰는 작업은 새로운 버전을 생성합니다.
- 오래된 버전은 vacuum/GC에 의해 정리됩니다.
이 때문에 PostgreSQL과 같은 시스템은 잠금 없이 읽을 수 있고 부하가 걸려도 잘 확장됩니다.
복구 과정
- 마지막 체크포인트를 읽습니다.
- WAL 레코드를 재생합니다.
- 미완료 트랜잭션을 롤백합니다.
- 일관성을 복원합니다.
이 과정은 결정적이며 반복 가능—추측이나 휴리스틱이 없습니다.
내부 구조를 이해하는 것이 중요한 이유
- 더 빠른 쿼리 작성
- 더 나은 스키마 설계
- 올바른 인덱스 선택
- 위험한 가정 피하기
- 성능 문제 디버깅
대부분의 “느린 데이터베이스” 문제는 다음에서 비롯됩니다:
- 잘못된 쿼리 계획
- 부적절한 인덱스
- 내부 구조 오해
…하드웨어 때문이 아닙니다.
Conclusion
실제 데이터베이스는 단순한 라이브러리보다 운영 체제에 가깝습니다. 메모리, 저장소, 동시성, 복구 및 스케줄링을 관리합니다. 이를 블랙 박스로 취급하면 불이익을 받게 되며, 내부 구조를 이해하면 소프트웨어 엔지니어링에서 가장 강력한 도구 중 하나가 됩니다.