Node.js 미드레벨 데이터베이스 기술면접
새 면접Q. Node.js 애플리케이션에서 사용자 주문 시스템을 설계할 때, 데이터베이스 정규화(Normalization)와 역정규화(Denormalization)의 개념을 설명하고, 각각을 선택해야 하는 상황과 트레이드오프를 설명해주세요. 특히 읽기와 쓰기 성능에 미치는 영향을 중심으로 설명해주세요.
정규화는 데이터 중복을 제거하고, 역정규화는 조회 성능을 위해 의도적으로 중복을 허용하는 것입니다.
정규화는 데이터 중복을 제거하고 데이터 무결성을 보장하기 위해 테이블을 분리하는 과정으로, 주문 테이블과 상품 테이블을 분리하여 상품 정보 변경 시 일관성을 유지합니다. 역정규화는 조인 비용을 줄이기 위해 의도적으로 중복 데이터를 저장하는 것으로, 주문 테이블에 주문 시점의 상품명과 가격을 함께 저장하여 조회 성능을 높입니다. 정규화는 쓰기 성능과 저장 공간 효율성이 좋지만 조인으로 인해 읽기 성능이 저하되고, 역정규화는 읽기 성능이 우수하지만 데이터 불일치 위험과 업데이트 비용이 증가합니다. 실무에서는 주문 이력처럼 변경되지 않는 과거 데이터는 역정규화하고, 마스터 데이터는 정규화하는 하이브리드 접근을 사용합니다. TypeORM이나 Sequelize에서 include를 과도하게 사용하면 N+1 문제가 발생하므로, 읽기가 많은 엔드포인트는 역정규화된 뷰나 집계 테이블을 활용하는 것이 효과적입니다.
- • 정규화는 데이터 중복 제거와 무결성 보장, 역정규화는 조회 성능 최적화
- • 정규화는 쓰기 우수/읽기 느림, 역정규화는 읽기 우수/쓰기 복잡
- • 실무에서는 데이터 특성에 따라 하이브리드 접근 사용
이커머스 주문 시스템에서 주문 이력 조회 성능을 위해 주문 시점의 상품 정보를 주문 테이블에 역정규화하여 저장합니다.
주문 시스템에서 상품 가격이 변경되었을 때, 과거 주문의 가격 정보를 어떻게 관리해야 할까요? 정규화와 역정규화 관점에서 각각의 접근 방법을 설명해주세요.
Q. Node.js에서 PostgreSQL 또는 MySQL을 사용할 때 트랜잭션 격리 수준(Isolation Level)의 네 가지 레벨인 Read Uncommitted, Read Committed, Repeatable Read, Serializable의 차이점을 설명하고, 각 레벨에서 발생할 수 있는 Dirty Read, Non-Repeatable Read, Phantom Read 문제를 설명해주세요. 또한 실무에서 격리 수준을 선택할 때 고려해야 할 점과 동시성과 일관성의 트레이드오프를 설명해주세요.
격리 수준이 높을수록 데이터 일관성은 보장되지만 동시성 성능은 저하되며, 각 레벨에서 방지할 수 있는 읽기 이상 현상이 다릅니다.
Read Uncommitted는 커밋되지 않은 데이터를 읽을 수 있어 Dirty Read가 발생하며, Read Committed는 커밋된 데이터만 읽지만 같은 트랜잭션 내에서 같은 쿼리가 다른 결과를 반환하는 Non-Repeatable Read가 발생합니다. Repeatable Read는 트랜잭션 시작 시점의 스냅샷을 읽어 Non-Repeatable Read를 방지하지만, 새로 삽입된 행이 나타나는 Phantom Read가 발생할 수 있으며, Serializable은 모든 읽기 이상 현상을 방지하지만 락으로 인해 동시성이 크게 저하됩니다. PostgreSQL의 기본값은 Read Committed이고 MySQL InnoDB는 Repeatable Read이며, 실무에서는 대부분 기본값을 사용하고 재고 차감 같은 중요한 작업에서만 Serializable이나 SELECT FOR UPDATE를 사용합니다. Sequelize에서는 transaction 옵션으로 격리 수준을 설정할 수 있으며, 높은 격리 수준은 데드락 위험을 증가시키므로 retry 로직과 타임아웃 설정이 필수입니다.
- • 격리 수준이 높을수록 일관성 보장, 낮을수록 동시성 우수
- • Dirty Read, Non-Repeatable Read, Phantom Read는 각 격리 수준에서 방지되는 범위가 다름
- • 실무에서는 기본 격리 수준 사용, 중요 작업에만 높은 수준 적용
결제 시스템에서 동시에 여러 사용자가 마지막 남은 상품을 구매할 때, 재고 일관성을 보장하기 위해 적절한 격리 수준과 락을 설정합니다.
Node.js에서 재고 차감 로직을 구현할 때 Lost Update 문제를 방지하기 위해 어떤 격리 수준과 락 전략을 사용해야 할까요? Optimistic Lock과 Pessimistic Lock의 차이도 함께 설명해주세요.
Q. Node.js 애플리케이션에서 사용자 검색 기능을 구현할 때, 단일 컬럼 인덱스와 복합 인덱스(Composite Index)의 차이점을 설명하고, 복합 인덱스의 컬럼 순서가 쿼리 성능에 미치는 영향을 설명해주세요. 특히 인덱스 최좌측 접두사 규칙(Leftmost Prefix Rule)이 무엇인지, 그리고 WHERE 절에 여러 조건이 있을 때 인덱스를 효율적으로 설계하는 방법을 설명해주세요.
복합 인덱스는 컬럼 순서가 중요하며, 첫 번째 컬럼부터 순서대로 사용되어야 인덱스가 효과적으로 활용됩니다.
복합 인덱스는 여러 컬럼을 조합하여 만든 인덱스로, (status, created_at) 순서로 만든 인덱스는 status만 조건으로 사용하거나 status와 created_at를 함께 사용할 때는 효과적이지만, created_at만 조건으로 사용하면 인덱스를 활용할 수 없습니다. 최좌측 접두사 규칙은 복합 인덱스의 첫 번째 컬럼부터 연속적으로 사용되어야 인덱스가 적용되는 규칙으로, 컬럼 순서를 결정할 때는 카디널리티가 높은 컬럼을 앞에 배치하거나, WHERE 절에서 등호(=) 조건이 먼저 오고 범위 조건이 나중에 오도록 설계합니다. 예를 들어 status는 몇 개의 값만 가지지만 user_id는 매우 다양하므로, (user_id, status, created_at) 순서가 (status, user_id, created_at)보다 효율적입니다. EXPLAIN 명령으로 실제 쿼리 실행 계획을 확인하여 인덱스가 사용되는지 검증해야 하며, TypeORM의 QueryBuilder나 Sequelize의 raw query에서도 동일한 원칙이 적용됩니다.
- • 복합 인덱스는 컬럼 순서가 중요하며 최좌측 접두사 규칙을 따름
- • 카디널리티가 높은 컬럼을 앞에, 등호 조건을 범위 조건보다 앞에 배치
- • EXPLAIN으로 쿼리 실행 계획을 검증하여 인덱스 활용 확인
게시판 검색 기능에서 작성자, 카테고리, 작성일 등 여러 조건으로 필터링할 때 복합 인덱스를 적절히 설계하여 조회 성능을 개선합니다.
WHERE status = 'active' AND created_at > '2024-01-01' ORDER BY created_at DESC LIMIT 10 쿼리를 최적화하기 위해 어떤 인덱스를 설계해야 할까요? 정렬과 페이징이 인덱스 설계에 미치는 영향도 함께 설명해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!