Django 리드·아키텍트 데이터베이스 면접

Django 리드 · 아키텍트 (10년+) 데이터베이스 3문항 조회수 23 · 2026-08-06 (목) 02:11:04
1 트랜잭션 격리 수준
Hard

Q. Django 서비스에서 주문과 재고 관리 시스템을 운영 중입니다. 동시에 여러 사용자가 마지막 남은 상품을 주문할 때 재고가 음수가 되거나 중복 판매되는 문제가 발생했습니다. PostgreSQL의 트랜잭션 격리 수준(READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE)을 각각 설명하고, Django에서 select_for_update()와 트랜잭션 격리 수준을 조합하여 이 문제를 해결하는 방법을 제시해주세요. 각 접근법의 성능과 데드락 위험성도 함께 논의해주세요.

동시성 제어에서 비관적 락과 낙관적 락의 차이, 그리고 격리 수준이 읽기 일관성에 미치는 영향을 고려해보세요.

A. 모범답안

PostgreSQL 기본값인 READ COMMITTED는 커밋된 데이터만 읽지만 같은 트랜잭션 내에서도 다른 결과를 반환할 수 있습니다. REPEATABLE READ는 트랜잭션 시작 시점의 스냅샷을 보장하며, SERIALIZABLE은 완전한 직렬화를 보장하지만 성능 오버헤드가 큽니다. Django에서는 select_for_update()로 행 단위 비관적 락을 걸어 재고 조회 시점부터 업데이트까지 다른 트랜잭션의 접근을 막을 수 있습니다. select_for_update(nowait=True)를 사용하면 락 대기 없이 즉시 예외를 발생시켜 사용자에게 품절 안내가 가능하고, skip_locked=True는 락 걸린 행을 건너뛰어 대기열 처리에 유용합니다. 또는 F() 표현식으로 UPDATE stock = stock - 1 WHERE stock > 0 같은 원자적 연산을 수행하거나, version 필드를 추가해 낙관적 락을 구현할 수 있습니다. 데드락 방지를 위해 항상 같은 순서로 테이블에 접근하고, 트랜잭션을 최대한 짧게 유지하며, 락 타임아웃을 설정해야 합니다.

핵심 포인트
  • PostgreSQL의 네 가지 격리 수준과 각각의 읽기 일관성 보장 범위
  • select_for_update()의 nowait, skip_locked 옵션 활용
  • F() 표현식을 통한 원자적 연산과 낙관적 락 패턴
  • 데드락 방지를 위한 락 순서 통일과 트랜잭션 최소화
답변에 넣으면 좋은 키워드
트랜잭션 격리 수준 select_for_update 비관적 락 낙관적 락 데드락 F() 표현식 REPEATABLE READ 원자적 연산
실무에서는

이커머스의 한정 수량 상품 판매나 예약 시스템에서 동시 접근 시 데이터 정합성을 보장해야 할 때 필수적입니다.

Follow-up 질문

분산 환경에서 여러 Django 인스턴스가 동일한 데이터베이스를 공유할 때, 애플리케이션 레벨 캐시와 데이터베이스 락 사이의 일관성 문제를 어떻게 해결하시겠습니까?

2 데이터베이스 파티셔닝
Hard

Q. 5년간 누적된 1억 건 이상의 주문 데이터를 가진 Django 서비스에서 최근 데이터 조회는 빠르지만 전체 기간 통계나 과거 데이터 조회 시 성능이 급격히 저하됩니다. PostgreSQL의 테이블 파티셔닝(Range, List, Hash) 전략을 설명하고, Django 환경에서 파티셔닝을 도입할 때 고려해야 할 마이그레이션 전략, ORM 쿼리 작성 시 주의사항, 그리고 파티션 프루닝(Partition Pruning)을 최대한 활용하기 위한 쿼리 패턴을 제시해주세요.

시계열 데이터의 특성과 파티션 키 선택이 쿼리 성능에 미치는 영향을 중심으로 생각해보세요.

A. 모범답안

Range 파티셔닝은 날짜나 ID 범위로 분할하여 시계열 데이터에 적합하고, List는 지역이나 카테고리 같은 명시적 값으로, Hash는 고른 분산이 필요할 때 사용합니다. 주문 데이터는 created_at 기준 월별 Range 파티셔닝이 적합하며, 오래된 파티션은 별도 테이블스페이스로 이동하거나 압축 저장할 수 있습니다. Django에서는 파티션 테이블을 직접 모델로 정의하지 않고 부모 테이블만 모델로 관리하며, 파티션 생성은 마이그레이션의 RunSQL이나 별도 스크립트로 처리합니다. 파티션 프루닝이 작동하려면 WHERE 절에 파티션 키가 반드시 포함되어야 하므로, 쿼리 작성 시 날짜 범위를 명시하고 함수나 연산을 파티션 키에 직접 적용하지 않아야 합니다. 기존 데이터 마이그레이션은 다운타임 없이 진행하기 위해 새 파티션 테이블을 먼저 생성하고, 배치로 데이터를 복사한 후 트리거로 동기화하며, 최종적으로 테이블명을 교체하는 전략을 사용합니다. 파티션별 인덱스 관리와 통계 정보 업데이트도 자동화해야 합니다.

핵심 포인트
  • Range, List, Hash 파티셔닝의 특징과 시계열 데이터에 적합한 전략
  • Django ORM에서 파티션 테이블 관리 방법과 마이그레이션 접근법
  • 파티션 프루닝을 위한 쿼리 작성 패턴과 파티션 키 사용 원칙
  • 무중단 데이터 마이그레이션과 파티션별 유지보수 자동화
답변에 넣으면 좋은 키워드
테이블 파티셔닝 Range 파티셔닝 파티션 프루닝 시계열 데이터 무중단 마이그레이션 파티션 키 RunSQL
실무에서는

대용량 로그, 주문 이력, IoT 센서 데이터 등 시간이 지남에 따라 누적되는 데이터를 효율적으로 관리하고 조회 성능을 유지해야 할 때 사용됩니다.

Follow-up 질문

파티셔닝된 테이블에서 여러 파티션에 걸친 JOIN 쿼리나 집계 쿼리의 성능을 최적화하려면 어떤 전략을 사용해야 할까요?

3 복합 인덱스 설계
Hard

Q. Django 서비스의 사용자 활동 로그 테이블(user_id, action_type, created_at, status, metadata)에서 다양한 필터 조합으로 검색이 이루어집니다. 단일 인덱스 여러 개와 복합 인덱스의 차이를 설명하고, 복합 인덱스의 컬럼 순서가 쿼리 성능에 미치는 영향을 분석해주세요. 또한 Partial Index, Covering Index, Expression Index의 개념과 Django 환경에서 이들을 언제 사용해야 하는지, 그리고 인덱스 비용(저장 공간, 쓰기 성능 저하)과 이점의 트레이드오프를 어떻게 판단할지 설명해주세요.

인덱스는 왼쪽부터 순차적으로 탐색된다는 점과, 실제 쿼리 패턴 분석이 인덱스 설계의 출발점임을 고려하세요.

A. 모범답안

복합 인덱스는 여러 컬럼을 하나의 인덱스로 묶어 특정 쿼리 패턴에 최적화되며, 컬럼 순서는 카디널리티가 높고 등호 조건이 먼저, 범위 조건은 나중에 배치하는 것이 일반적입니다. 예를 들어 WHERE user_id = X AND created_at > Y 쿼리에는 (user_id, created_at) 순서가 적합하며, 첫 번째 컬럼만으로도 인덱스를 활용할 수 있지만 두 번째 컬럼부터 시작하는 쿼리는 인덱스를 사용하지 못합니다. Partial Index는 WHERE status = 'active' 같은 조건을 인덱스에 포함시켜 특정 부분집합만 인덱싱하여 크기를 줄이고, Covering Index는 SELECT 절의 모든 컬럼을 인덱스에 포함시켜 테이블 접근 없이 인덱스만으로 쿼리를 처리합니다. Expression Index는 LOWER(email)이나 DATE(created_at) 같은 함수 결과에 인덱스를 생성하며, Django에서는 Meta.indexes에 Index 클래스로 정의할 수 있습니다. 인덱스는 INSERT, UPDATE, DELETE 시 추가 오버헤드가 발생하고 저장 공간을 차지하므로, 실제 쿼리 로그를 분석하여 빈도가 높고 성능 영향이 큰 쿼리에만 선택적으로 적용하며, EXPLAIN ANALYZE로 실행 계획을 검증해야 합니다.

핵심 포인트
  • 복합 인덱스의 컬럼 순서 원칙과 왼쪽 프리픽스 규칙
  • Partial, Covering, Expression Index의 특징과 적용 시나리오
  • Django Meta.indexes를 통한 인덱스 정의와 마이그레이션
  • 쿼리 로그 분석과 EXPLAIN ANALYZE 기반 인덱스 효과 검증
  • 인덱스 비용과 이점의 트레이드오프 판단 기준
답변에 넣으면 좋은 키워드
복합 인덱스 컬럼 순서 Partial Index Covering Index Expression Index 카디널리티 EXPLAIN ANALYZE 인덱스 오버헤드
실무에서는

검색 기능이 많은 어드민 페이지나 다양한 필터 조합이 필요한 대시보드에서 각 쿼리 패턴에 최적화된 인덱스를 설계할 때 필수적입니다.

Follow-up 질문

인덱스가 많은 테이블에서 옵티마이저가 잘못된 인덱스를 선택하거나 인덱스를 사용하지 않는 경우, 어떻게 문제를 진단하고 해결하시겠습니까?

댓글 0

로그인 후 댓글을 작성할 수 있습니다.

아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!