데이터베이스 — 백엔드 면접 (실제 기출 기반·심화)
DB는 한국 백엔드 면접에서 가장 자주·가장 깊게 묻는다. "인덱스가 왜 빠른가", "B+트리", "트랜잭션 ACID", "격리수준", "낙관적 vs 비관적 락", "N+1", "정규화" — 단골이고, VSFe 패턴으로 복합 인덱스 선두 컬럼·조인 알고리즘·격리수준 엔진별 차이까지 파고든다.
"인덱스를 왜 수정 잦은 테이블엔 안 쓰나?", "REPEATABLE READ면 Phantom이 발생하나?" 같은 함정형 질문이 많다.
1. 인덱스 — B+트리·복합·클러스터 (★★★ 최빈출)
실제 질문: "인덱스는 수정이 잦은 테이블엔 쓰지 말라는데 왜?" · "ORDER BY/GROUP BY를 인덱스와 연관지어 설명하라." · "(A, B) 복합 인덱스에서 A 없이 B만으로 쿼리하면 인덱스를 타나요?" · "기본키는 인덱스인가요?" (VSFe — 매우 디테일)
- B+트리 인덱스: 정렬된 자료구조 → 탐색·범위·정렬 O(log N). 리프에만 값이 있고 리프가 연결리스트로 이어져 범위 검색·ORDER BY에 강함. (B-트리는 모든 노드에 값 → 범위 약함.)
- 왜 해시가 아니라 B+트리? 해시는 등호(=)만 되고 부등호·범위·
LIKE·정렬 불가 → B+트리. - 복합 인덱스 선두 컬럼 법칙(★): (A, B)는 A로 먼저 정렬 후 B라 A 조건 없이 B만으론 인덱스를 못 탄다.
- 클러스터형 vs 보조(비클러스터형): 클러스터형은 데이터 자체가 PK 순으로 정렬(테이블당 1개), 보조 인덱스는 별도 구조 + PK(또는 포인터)로 재탐색.
깊이 — DML 페널티: INSERT(인덱스 분할/재정렬)·DELETE(실제 삭제 안 하고 사용 안 함 표시만 → 테이블·인덱스 수 불일치·조각화)·UPDATE(Delete+Insert). → 수정 잦은 테이블엔 인덱스 비용↑.
꼬리질문: "오름차순 인덱스로 내림차순 정렬은?" → 리프를 역방향 스캔(대부분 가능·약간 비용). / "인덱스 조각화 해결?" → 재구성(REBUILD). / "커버링 인덱스?" → 필요한 컬럼이 인덱스에 다 있으면 테이블 접근 없이 인덱스만으로 응답.
함정: ❌ "인덱스는 많을수록 좋다" → DML 페널티·카디널리티 낮은 컬럼은 역효과. ❌ "해시가 O(1)이라 항상 빠르다" → 범위·정렬 불가.
2. 트랜잭션·ACID (★★ 단골)
실제 질문: "트랜잭션과 ACID를 설명하라." · "Durability를 DBMS는 어떻게 보장하나요?" · "읽기에도 트랜잭션을 걸어야 하나요?" (VSFe·gyoogle)
- 원자성(All-or-Nothing·Commit/Rollback)·일관성(제약 유지)·격리성(동시 트랜잭션 간섭 차단·격리수준으로 조절)·지속성(커밋 후 영구).
- Durability 보장(★): WAL(Write-Ahead Logging) — 데이터 페이지를 디스크에 쓰기 전에 Redo 로그를 먼저 기록 → 장애 시 로그로 복구. Undo(실패 취소)/Redo(커밋 재반영).
꼬리질문: "모든 페이지를 즉시 디스크에 쓰면 안전하지 않나?" → I/O 병목 → 로그 기반(순차 쓰기). / "읽기에 트랜잭션?" → 일관된 스냅샷·반복 읽기 보장에 필요(격리수준).
함정: ❌ "지속성 = 메모리에 유지" → 디스크 로그로 영구 보장.
3. 격리수준·이상현상 (★★★ 단골·함정)
실제 질문: "격리 수준의 종류와 각 수준에서 발생 가능한 이상현상은?" · "모든 DBMS가 4레벨을 다 구현하나요?" · "MySQL InnoDB의 Undo/Redo를 설명하라." (VSFe·gyoogle)
| 레벨 | 막는 이상현상 | 비고 |
|---|---|---|
| READ UNCOMMITTED | (없음) | Dirty Read 발생 |
| READ COMMITTED | Dirty Read | Oracle/PostgreSQL 기본 |
| REPEATABLE READ | + Non-Repeatable Read | MySQL InnoDB 기본 |
| SERIALIZABLE | + Phantom Read | 최고 격리·최저 동시성 |
- Dirty Read(미커밋 읽기)·Non-Repeatable Read(같은 행 재조회 값 변경)·Phantom Read(범위 재조회 시 새 행 출현).
깊이 — MySQL InnoDB의 함정(★): 표준상 REPEATABLE READ에선 Phantom Read가 발생하지만, MySQL InnoDB는 RR에서도 Phantom을 대부분 막는다 — 단 막는 메커니즘이 읽기 종류에 따라 다르다: ① **일반 SELECT(non-locking)**는 MVCC 스냅샷으로 새 행을 안 본다(락 없음) ② **잠금 읽기(SELECT … FOR UPDATE/UPDATE/DELETE)**는 **Next-Key Lock(레코드 락 + 갭 락)**으로 범위에 새 행 삽입을 차단한다. 이 이원 구조를 아는지가 변별점. (PostgreSQL의 RR은 스냅샷 격리라 Phantom은 막지만 write skew(두 트랜잭션이 서로의 미반영 결과에 기반해 제약을 깨는 현상)는 SERIALIZABLE/SSI 필요.)
꼬리질문: "MVCC란?" → 버전을 둬 읽기는 락 없이 일관된 스냅샷(Undo로 과거 버전 복원). / "격리수준↑의 대가?" → 동시성↓·락↑.
함정: ❌ "RR이면 Phantom이 무조건 발생" → MySQL InnoDB는 대부분 막음. ❌ "MySQL 기본은 READ COMMITTED" → REPEATABLE READ.
4. 락 — 낙관적 vs 비관적 (★★ 단골)
실제 질문: "Optimistic Lock과 Pessimistic Lock을 설명하라." · "물리 락 수행 중 비정상 종료로 락이 안 풀리면 DB는 어떻게 해결하나요?" (VSFe)
- 낙관적 락: 충돌이 드물다 가정.
@Version컬럼으로UPDATE ... WHERE id=? AND version=?→ 버전 불일치면OptimisticLockException. DB 락 없이 애플리케이션 레벨 → 재시도 로직 필수. - 비관적 락: 충돌이 잦다 가정. **
SELECT ... FOR UPDATE**로 DB 배타락 선점.
깊이: 선택 기준 — 고충돌(티켓팅·선착순) → 비관적, 저충돌(일반 주문) → 낙관적. 비관적 락은 데드락(순환 대기) 위험, 낙관적 락은 충돌 잦으면 재시도 폭증.
꼬리질문: "비정상 종료로 락이 안 풀리면?" → 트랜잭션 타임아웃·세션 종료 시 자동 해제 + 데드락 탐지(victim 롤백). / "분산 환경에서 DB 락만으로 충분?" → 부족 → Redis 분산락(캐시·시스템설계 편). / "갭/넥스트키 락?" → InnoDB가 범위에 락을 걸어 Phantom 방지.
함정: ❌ "낙관적 락도 DB 락을 건다" → 애플리케이션 레벨(버전 비교). ❌ "락을 걸면 데드락이 없다" → 비관적 락이 데드락 유발.
5. 정규화·반정규화 (★ 단골)
실제 질문: "정규화를 안 하면 발생하는 이상현상은?" · "정규화가 무조건 좋은가요? 언제 반정규화하나요?" (VSFe·gyoogle)
- 이상현상: 삽입 이상(불필요 데이터 강제)·갱신 이상(일부만 수정→불일치)·삭제 이상(필요 데이터 소실).
- 단계: 1NF(원자값) → 2NF(부분 함수 종속 제거·복합키) → 3NF(이행 종속 A→B→C 제거) → BCNF(모든 결정자가 후보키).
- 반정규화: 조인 비용 절감을 위해 의도적 중복 허용(조회 성능 최적화).
꼬리질문: "정규화의 대가는?" → 테이블 분리 → 조인 증가 → 조회 성능↓. 실무는 보통 3NF + 필요 시 반정규화. / "2NF vs 3NF?" → 부분 종속(복합키) vs 이행 종속.
함정: ❌ "정규화는 항상 옳다" → 조인 비용 트레이드오프. ❌ "1NF가 부분 종속 제거" → 1NF는 원자값.
6. 조인·실행계획·N+1 (★★ 단골)
실제 질문: "JOIN의 내부 구현(Nested Loop/Sort Merge/Hash)을 설명하라." · "인덱스를 탈 수 있는데도 Full Scan으로 동작하는 경우는?" · "COUNT(1), COUNT(*), COUNT(column) 차이는?" (VSFe)
- 조인 알고리즘: Nested Loop(소량·인덱스 있을 때)·Sort Merge(양쪽 정렬 후 병합·대량)·Hash Join(등가 조인·대량·한쪽 해시테이블).
- Full Scan 선택 이유(★): 옵티마이저가 비용 기반(CBO) → 선택도가 낮을 때(읽을 행 비율이 높을 때·랜덤 I/O보다 순차 스캔이 쌈)·통계 오래됨·인덱스 컬럼에 함수/형변환(
WHERE DATE(col)=…) 적용 시 인덱스 무력화. - COUNT:
COUNT(*)=COUNT(1)(전체 행),COUNT(column)은 NULL 제외. - N+1(JPA): 연관 엔티티를 1건씩 추가 쿼리로 N번 조회 → Fetch Join·@BatchSize·@EntityGraph(Spring·JPA 편).
꼬리질문: "조인 순서는 누가 정하나?" → 옵티마이저(비용 기반). / "조인 조건 빠지면?" → 카테시안 곱 폭발. / "함수 인덱스로 해결?" → 인덱스에 표현식을 미리 계산(함수 기반 인덱스).
함정: ❌ "COUNT(column)=COUNT(*)" → NULL 제외. ❌ "인덱스만 있으면 항상 탄다" → 함수·형변환·낮은 선택도면 풀스캔.
7. NoSQL vs RDB·샤딩·복제 (★ 단골)
실제 질문: "NoSQL의 강점·약점은?" · "RDB의 어떤 특징 때문에 NoSQL 대비 부하가 걸리나요?" · "레플리케이션 vs 샤딩 중 무엇을 쓸 건가요?" · "마스터-슬레이브 동기화 전 데이터 정합성은?" (VSFe·WeareSoft)
- RDB(고정 스키마·조인·정규화·ACID·수직확장) vs NoSQL(스키마리스·조인 없이 중복 저장·수평확장·BASE/최종일관성). RDB 부하 원인 = 조인·정규화 연산·스케일아웃 어려움.
- 파티셔닝(한 DB 내 분할: 수평=행/수직=컬럼) vs 샤딩(여러 DB 서버 분산) vs 레플리케이션(복제로 읽기 분산·가용성).
깊이: 마스터-슬레이브 복제 지연(replication lag) 동안 슬레이브를 읽으면 stale → 쓰기 직후 읽기는 마스터로(read-your-writes·시스템설계 편).
꼬리질문: "샤딩 단점?" → 샤드 간 조인·트랜잭션 불가·리밸런싱·글로벌 유니크 키. / "복제는 쓰기 확장이 되나?" → 안 됨(쓰기는 마스터 한 곳) → 샤딩.
함정: ❌ "NoSQL은 항상 빠르고 좋다" → 트랜잭션·복잡 조인·정합성엔 RDB 우위. ❌ "복제로 쓰기 부하 분산" → 읽기만.
8. MongoDB·정산 원장·읽기 모델 (★ 기출·채용공고 보강·2026-07)
실제 질문: "MongoDB를 간단히 설명하라·언제 쓰나?" (ksundong) · "정산 데이터를 어떻게 모델링해 과거를 재계산하지 않고 감사할 수 있게 하나?" · "주문 조회가 N+1·과도 조인으로 느리다 — 쿼리 튜닝을 넘어 데이터/읽기 모델을 어떻게 바꾸나?" (prime-career 커머스/물류 공고)
MongoDB(문서형 NoSQL): JSON류 BSON 문서를 컬렉션에 저장. 스키마 유연(문서마다 필드 상이 허용)·수평 확장(샤딩). 모델링은 임베딩(embedding, 한 문서에 중첩) vs 참조(referencing, ID로 분리) 선택 — 함께 읽는 데이터·1:소수는 임베딩(단일 읽기·조인 없음), 독립 변경·1:다수·큰 배열은 참조. 인덱스(단일·복합·다중키·텍스트), 4.0+ 멀티도큐먼트 트랜잭션 지원(단 RDBMS만큼 저렴하진 않음). 언제: 스키마가 자주 변하는 반정형 데이터·문서 단위 접근·빠른 개발. 부적합: 복잡한 다중 엔터티 조인·강한 관계 정합성(→ RDBMS). 꼬리질문: "조인은?" → $lookup 있으나 비싸므로 임베딩/비정규화로 회피가 정석.
정산 원장(ledger) — append-only 불변 기록: 결제/정산/포인트처럼 금전·감사가 걸린 도메인은 최종 잔액만 UPDATE하지 말고 불변 이벤트(거래)를 append하고 잔액은 그 합/스냅샷으로 파생한다. 핵심 규칙: ① 규칙(요금·수수료)이 바뀌어도 과거 거래를 재계산하지 않는다(거래 시점 규칙이 법·회계 기준) → 정정은 조정 거래(adjustment/reversal) 를 추가로 append(원본 보존), ② 각 거래에 rule_version·입력 스냅샷·provenance를 함께 저장해 결정론적 재현·감사 가능, ③ 이중 정산 방지는 멱등 키 + UNIQUE. 복식부기(차변=대변) 불변식으로 정합성을 검증하기도. 복제/조회는 원장에서 파생한 잔액 스냅샷으로.
CQRS·읽기 모델(read model): 쓰기(정규화·정합성)와 읽기(화면별 최적화)의 요구가 충돌할 때 분리한다. N+1·과도 조인이 반복되면 범용 API 하나로 모든 화면을 커버하려다 조인이 폭발하므로, 화면/목적별 읽기 모델(비정규화 뷰·검색 인덱스·머티리얼라이즈드 뷰)을 두고 쓰기 이벤트(도메인 이벤트/CDC)로 갱신한다. 쓰기 모델이 진실의 원천, 읽기 모델은 최종 일관성(수백 ms 지연 허용). 꼬리질문: "일반 캐시와 뭐가 다른가?" → 캐시는 같은 모델의 사본, 읽기 모델은 다른 스키마로 재구성(조인 미리 수행). "읽기 모델이 뒤처지면?" → 로그/이벤트가 원천이라 재구성 가능·중요 화면은 read-your-writes 보정.
함정: ❌ "NoSQL은 조인이 공짜" → 임베딩/비정규화로 회피가 정석, $lookup은 비쌈. ❌ "정산은 잔액만 UPDATE" → 감사·정정 불가 → 불변 원장 + 조정 거래. ❌ "N+1은 인덱스로만 해결" → 읽기 모델 분리가 근본책.
(출처: MongoDB — data modeling·transactions·Kleppmann DDIA(파생 데이터·CQRS·이벤트 소싱)·microservices.io — CQRS 교차검증. 기출·실무 프레이밍: docs/01·docs/04·05.)
흔한 오답·함정 정리
- 인덱스는 많을수록 좋다 → DML 페널티·낮은 선택도 역효과.
- MySQL 기본 격리수준은 READ COMMITTED → REPEATABLE READ(InnoDB는 Phantom도 대부분 막음).
- 낙관적 락도 DB 락을 건다 → 애플리케이션 레벨(버전).
COUNT(column)=COUNT(*)→ column은 NULL 제외.- 정규화는 항상 옳다 → 조인 비용 트레이드오프(반정규화).
한국 면접 단골 Q&A (답변 골격)
| 질문 | 핵심 답 |
|---|---|
| 인덱스 왜 빠른가 | B+트리 정렬·리프 연결·범위/정렬 O(log N) |
| 복합 인덱스 선두 컬럼 | A 없이 B만으론 못 탐 |
| 인덱스 단점 | DML 페널티·조각화·낮은 선택도 |
| ACID·Durability | 원자/일관/격리/지속·WAL/Redo |
| 격리수준·이상현상 | RU/RC/RR/SER·Dirty/NonRepeat/Phantom |
| MySQL RR Phantom | MVCC+Next-Key로 대부분 막음 |
| 낙관 vs 비관 락 | 버전 비교(재시도) vs SELECT FOR UPDATE |
| 정규화·반정규화 | 이상현상 제거 vs 조인비용↓ 중복 |
| 조인 알고리즘 | Nested Loop/Sort Merge/Hash |
| Full Scan 이유 | 낮은 선택도·통계·함수 인덱스 무력화 |
| 샤딩 vs 복제 | 쓰기/용량 분산 vs 읽기/가용성 |
꼬리질문 대비 (상 난이도)
- "왜 인덱스에 B+트리?" → 범위·정렬·부등호(해시는 등호만).
- "MySQL RR에서 Phantom?" → MVCC+넥스트키로 대부분 차단(표준과 다름).
- "락 비정상 종료?" → 타임아웃·세션 종료·데드락 탐지 롤백.
- "Full Scan이 더 빠를 때도?" → 대부분 행을 읽으면 랜덤 I/O보다 순차 풀스캔이 유리.
- "분산 트랜잭션?" → 2PC(블로킹)·Saga(보상·시스템설계 편).
한 줄 요약 — 인덱스는 B+트리(범위/정렬·복합은 선두 컬럼·DML 페널티·클러스터/보조). ACID·Durability=WAL/Redo. 격리수준 RU/RC/RR/SER·이상현상, MySQL InnoDB는 RR이 기본이고 MVCC+넥스트키로 Phantom 대부분 차단. 락은 낙관(버전·재시도)/비관(FOR UPDATE·데드락). 정규화(이상현상)↔반정규화(조인비용). 조인 Nested/Merge/Hash·Full Scan은 선택도/함수. NoSQL/RDB·샤딩(쓰기)/복제(읽기·지연).
(출처 — 한국 면접 기출·교차검증 2026-06: VSFe/Tech-Interview — Database·gyoogle — Database·WeareSoft — db·haon.blog 낙관/비관 락 · MySQL 8.0 — 격리수준·Phantom Rows·Next-Key Locking·PostgreSQL 문서 교차검증.)