포스트

DB 로드맵 — 설계·동시성·성능·운영·분산, 다섯 질문으로 나눈 글 지도

DB 글 28편을 '각 구역이 답하는 질문' 하나로 갈랐다. 데이터를 어떻게 담나(설계) → 동시 접근을 어떻게 안전하게(트랜잭션·동시성) → 어떻게 빨리 읽나(성능) → 어떻게 살려두나(운영) → 여러 노드로 어떻게(분산). 추상 대 응용으로 나누지 않고 질문으로 나눠, 한 글이 두 구역에 걸치지 않게 했다. 애플리케이션 연동과 장애 트러블슈팅은 결이 다른 축이라 부록으로 분리.

DB 로드맵 — 설계·동시성·성능·운영·분산, 다섯 질문으로 나눈 글 지도

DB는 “쿼리 짜는 법”에서 멈추기 쉽다. 그런데 한 겹만 걷어내면 — 데이터를 어떻게 담고, 동시 트랜잭션을 어떻게 안전하게 다루고, 어떻게 빨리 읽고, 운영 중 어떻게 살려두고, 여러 노드로 어떻게 확장하는지 — 서비스의 안정성과 성능이 갈린다. 이 블로그의 DB 글 28편을 그 다섯 질문으로 묶었다. 본인 위치에서 가까운 구역부터 진입하면 된다.

나눈 기준은 “추상이냐 응용이냐”가 아니라 “무슨 질문에 답하느냐”다. 인덱스를 이해하는 것과 거는 것을 원리·성능으로 찢으면 경계가 흐려진다 — 둘 다 “어떻게 빨리 읽나”라는 한 질문의 답이기 때문이다. 그래서 구역마다 질문을 하나씩 걸고, 그 질문에 답하는 글만 넣었다. 한 글이 두 구역에 걸치지 않는다.

설계 → 동시성 → 성능 → 운영 → 분산이 데이터를 다루는 자연스러운 흐름이자 실력이 쌓이는 학습 줄기다. 애플리케이션과 DB를 잇는 도구·연동, 그리고 특정 장애 트러블슈팅은 이 질문들 어디에도 안 들어가는 결이 다른 축이라 아래 부록으로 분리했다 — 학습 흐름과 별개로, 필요할 때 찾아 들어오면 된다.

전제와 범위 — 이 로드맵은 SELECT·JOIN·GROUP BY 같은 기본 SQL은 쓸 줄 안다고 보고 그 위층부터 시작한다. 두 갈래는 의도적으로 줄기 밖에 뒀다: 윈도우 함수·CTE·재귀 쿼리 같은 SQL 작성 심화(어떻게 작성하나는 여기서 안 다루고, 어떻게 실행·튜닝하나만 성능 구역에서 짚는다), 그리고 heap/page 레이아웃·buffer·WAL 같은 저장 엔진 물리 내부(인덱스·MVCC 글이 필요한 만큼만 걸치고, 그 자체를 독립 구역으로 두진 않았다).

한눈에 보기

다섯 구역은 각각 질문 하나에 답한다. 이 질문이 곧 “이 글이 왜 여기 있나”의 답이다. 부록은 이 질문들 밖의 다른 축이다.

구역답하는 질문성격
설계데이터를 어떻게 담나줄기
트랜잭션·동시성동시 접근을 어떻게 안전하게줄기
성능어떻게 빨리 읽나줄기
운영어떻게 살려두나줄기
분산여러 노드로 어떻게줄기
부록 A도구·연동 — MyBatis·JPA·Liquibase·Kibana다른 축
부록 B연결·성능 장애 트러블슈팅다른 축

설계 — 데이터를 어떻게 담나

무엇을 최적화하기 전에, 데이터를 어떤 모양으로 담을지부터. 스키마를 잘못 잡으면 이후의 모든 쿼리·성능 판단이 그 위에서 흔들린다. 정규화로 이상 현상을 없애고, 필요하면 의도적으로 되돌리는(역정규화) 트레이드오프가 이 구역의 전부다.

핵심
정규화와 스키마 설계 — 1NF~BCNF와 역정규화함수 종속으로 이해하는 정규형이 이상 현상을 없애는 원리와, 읽기 성능을 위해 조인을 줄이는 역정규화 트레이드오프
RECORD_ID를 레벨 테이블에 사전 적재해 조인 제거수천만 건 팩트 테이블 JOIN을 INSERT 시점에 미리 옮겨 조회 시 JOIN 자체를 없애는 설계. 위 역정규화 트레이드오프를 극단까지 민 실전 사례

정규화로 “왜 나누는가”를 잡고, 사전 적재로 “언제 되돌리는가”를 본다. 설계는 이 둘 사이의 판단이다.

트랜잭션·동시성 — 동시 접근을 어떻게 안전하게

여러 트랜잭션이 같은 데이터를 동시에 건드릴 때 무엇이 깨지고, DB가 그걸 어떻게 막는지. 성능을 논하기 전에 서야 하는 정합성의 토대다 — 격리 수준이 무엇을 막아주는지 모르면 이후 튜닝은 “빠른데 틀린” 결과로 흐른다.

핵심
트랜잭션 동시성 제어 — 격리 수준과 락Schedule·Serializability, S/X Lock과 2PL, READ COMMITTED·REPEATABLE READ·SERIALIZABLE이 각각 막아주는 이상 현상을 한 흐름으로
MVCC와 VACUUM격리 수준이 xmin/xmax·스냅샷으로 구현되는 방식과, 그 대가인 dead tuple·bloat를 청소하는 VACUUM·autovacuum·wraparound

격리 수준이 “무엇을 막나”라면, MVCC는 “그걸 어떻게 구현하나”, VACUUM은 “그 구현의 대가를 어떻게 치르나”다. 격리·MVCC·VACUUM이 한 흐름의 동시성 이야기다.

성능 — 어떻게 빨리 읽나

여기가 실무 시간의 대부분이 쏠리는 구역이다. 엔진이 테이블을 어떻게 이어 붙이고 인덱스로 찾고 실행 계획을 세우는지(원리)부터, 그 원리를 근거로 파티셔닝·쿼리·커넥션·캐시를 다루는 데(응용)까지 — “빨리 읽기”라는 한 질문의 답이라 한 구역에 뒀다.

핵심
RDB 조인(Join) 방식 총정리Nested Loop·Hash·Sort-Merge의 원리·시간 복잡도·메모리 패턴, 옵티마이저가 테이블 크기·인덱스·정렬 상태로 전략을 고르는 기준
RDB 인덱스 완전 정리B+tree 구조가 조회를 O(log N)으로 만드는 원리, 복합 인덱스 선두 컬럼 규칙, 커버링 인덱스, 그리고 인덱스를 만들고도 풀스캔이 도는 흔한 이유들
쿼리 옵티마이저 작동 원리와 실행계획(EXPLAIN) 읽기비용 기반 옵티마이저가 통계로 카디널리티를 추정해 계획을 고르는 원리, EXPLAIN/ANALYZE로 추정과 실제의 괴리를 읽어 튜닝
실행계획(EXPLAIN) 노드·필드 사전EXPLAIN에 뜨는 스캔·조인·집계·정렬 노드와 Buffers·Heap Fetches·Sort Method 계측 라인을 찾아보는 레퍼런스. 위 옵티마이저 글의 짝
쿼리 튜닝 — 페이지네이션·N+1OFFSET이 깊은 페이지에서 느려지는 이유와 keyset 대안, ORM에서 흔한 N+1을 조인·배치 로딩으로 없애기
테이블 파티셔닝Range·List·Hash로 대용량 테이블을 나누고 파티션 프루닝으로 스캔량을 줄이는 설계. 오래된 파티션 DROP으로 대량 삭제를 순식간에
DBCP — HikariCP 커넥션 풀 사이징minimumIdle·maximumPoolSize·maxLifetime이 DB의 max_connections·wait_timeout과 맞물리는 방식, 적정 커넥션 수를 부하 테스트로 찾는 흐름
DB 앞단 캐싱 전략 — RedisCache-Aside·Write-Through 패턴과 무효화, DB-캐시 정합성, 스탬피드·침투·핫키 장애 대응

📎 치트시트 · sql-snippets — information_schema·인덱스·튜닝 실전 SQL 빠른 참조 (GitHub)

조인·인덱스·옵티마이저로 “엔진이 어떻게 찾나”를 잡으면, 파티셔닝·쿼리 튜닝이 왜 그렇게 동작하는지, 커넥션·캐시를 앞단에 어떻게 두는지가 원리 위에서 읽힌다. 설계 구역의 사전 적재가 왜 “옵티마이저를 이기는” 게 아니라 “옵티마이저가 일할 필요를 없애는” 설계인지도 여기 조인 원리를 알아야 보인다.

운영 — 어떻게 살려두나

설계·성능이 끝나도 DB는 살아 움직인다. 백업을 걸고, 원하는 시점으로 되돌리고, 복제로 이중화하고, 지표를 보고, 버전을 올리는 — 운영 중 마주치는 관문들. 정석 순서(백업 → 시점 복구 → 복제 → 모니터링 → 업그레이드)로 뒀고, 일회성 작업인 마운트 경로 이전은 맨 뒤에 부수적으로 둔다.

핵심
pg_dump / pg_restore 사용법plain/custom/directory/tar 포맷 선택 기준, psql로는 plain만 복원되는 이유, pg_restore의 병렬(-j)·선택 복원(-n/-t)
PITR와 백업 전략pg_dump 논리 백업을 넘어 WAL 아카이빙·pg_basebackup으로 원하는 시점으로 복구하는 PITR과 RPO/RTO 설계
복제와 고가용성스트리밍 복제가 WAL을 standby로 흘려보내는 원리, 동기·비동기 트레이드오프, 읽기 복제본의 replication lag, failover 승격
모니터링 — pg_stat·슬로우 쿼리pg_stat_activity·user_tables·pg_stat_statements로 느린 쿼리·안 쓰는 인덱스·dead tuple·복제 지연을 잡기
PostgreSQL 메이저 업그레이드 14→17왜 바이너리 교체만으로 안 되는지, pg_upgrade --link vs dump/restore 트레이드오프, encoding·locale 관문과 --check→실행 절차
PostgreSQL 마운트 경로(PGDATA) 변경데이터 디스크 분리·이전을 위해 PGDATA를 옮기는 절차. 서비스 중지 → 디렉토리 이동 → systemd Environment=PGDATA 수정 → 재시작 → SHOW data_directory 확인. 상시 관문이 아니라 디스크를 옮길 때만 찾는 일회성 작업

분산 — 여러 노드로 어떻게

단일 DB를 넘어 여러 노드로 갈 때 반드시 부딪히는 이론. 실무 결정(어떤 스토어를 고를지)의 밑그림이 된다.

핵심
CAP 정리 — P는 고르는 게 아니라 주어진다CAP은 셋 중 둘 고르기가 아니라 파티션 발생 시 일관성·가용성 중 무엇을 살릴지의 문제. CA/CP/AP의 실제 의미와 PACELC까지
분산 DB 확장 — 샤딩·분산 트랜잭션·합의샤드 키로 여러 노드에 나눌 때의 원자성 문제를 2PC·Saga로, 복제 노드의 동의를 Raft로 — CAP 이후의 실무 확장
NoSQL 개요 — 문서·키밸류·컬럼·그래프네 가지 NoSQL 데이터 모델과 적합 사례, ACID vs BASE·최종 일관성, 스키마·조인·확장 기준으로 RDB와 고르기

부록 A — 도구·연동 (다른 축)

여기서부터는 위 다섯 질문 어디에도 안 들어가는 다른 축이다 — 애플리케이션과 DB를 잇는 매핑(MyBatis·JPA)·마이그레이션(Liquibase), 그리고 성격이 또 다른 데이터 관측·시각화(Elasticsearch/Kibana). 학습 흐름과 분리해, 해당 도구를 붙일 때 찾아 들어오면 된다.

핵심
MyBatis 사용 패턴 기록시퀀스 채번, 1:N 컬렉션 매핑, ${} vs #{} 차이, Map 동적 컬럼 바인딩 등 실사용 중 마주친 패턴들
JPA/ORM 핵심 — 영속성 컨텍스트·지연 로딩·N+1영속성 컨텍스트의 1차 캐시·변경 감지, 지연 로딩 프록시, N+1을 fetch join·@EntityGraph·@BatchSize로 없애기. MyBatis와 대비되는 ORM 접근
Liquibase 설정과 사용 패턴master.xml 구성, changeset 작성 규칙, CSV·타임스탬프 처리 등 스키마 마이그레이션 실무 패턴
Kibana 개념 정리 — Saved Objects·Lens·Alerting환경 간 대시보드 이전(Saved Objects), 차트별 적합 데이터, Index threshold·ES query 룰, 7.x→8.x 변화

📎 치트시트 · kibana · elasticsearch — KQL·Dev Tools / ES 쿼리·관리 빠른 참조 (GitHub)

부록 B — 트러블슈팅 (다른 축)

학습 줄기와 분리해 둔다. 특정 에러·성능 장애로 막혔을 때 직행하는 글들.

핵심
IntelliJ DB SSH 터널 — JDBC URL 주의점내장 SSH 터널 사용 시 JDBC URL에 localhost가 아니라 베스천에서 본 원격 주소를 넣어야 하는 이유
ORA-12514 리스너 서비스 오류리스너까지는 붙었는데 서비스 이름이 없어 나는 오류를 PMON 동적 등록부터 lsnrctl 진단까지
Vertica에서 OR 조건 JOIN은 성능을 죽인다LEFT OUTER JOIN의 ON 절 OR가 Join Filter로 빠지며 풀스캔이 나는 문제와, outer join 의미를 보존한 매칭 쌍 분리 해법. 성능 구역 조인 원리의 “장애” 각도

본인 위치에 따라:

  • 테이블을 어떻게 나눌지 감이 안 잡히면 설계 구역 — 정규화와 역정규화 트레이드오프부터.
  • 동시 트랜잭션이 데이터를 깨뜨릴까 불안하면 트랜잭션·동시성 — 격리 수준·MVCC·VACUUM.
  • 쿼리가 왜 느린지, 어떻게 빠르게 할지가 급하면 성능 구역 — 조인·인덱스·옵티마이저 원리 위에 파티셔닝·튜닝·커넥션·캐싱.
  • 운영 중 백업·복제·모니터링·업그레이드가 닥쳤다면 운영 구역으로 직행.
  • 분산 스토어 선택·확장의 밑그림이 필요하다면 분산 구역 — CAP·샤딩·NoSQL.
  • MyBatis·JPA·Liquibase·Kibana를 붙이는 중이라면 부록 A(도구·연동).
  • 특정 에러(ORA-12514, SSH 터널, Vertica 조인)로 막혔다면 부록 B(트러블슈팅)로 바로.

조인은 이 세 구역을 관통한다 — 성능에서 전략을 이해하고, 설계에서 회피하고, 부록 B의 Vertica 사례로 장애를 피한다. 세 각도를 함께 보면 조인을 입체적으로 다룰 수 있다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.