운영체제 미드레벨 데이터베이스 기술면접
새 면접Q. 대용량 사용자 테이블에서 이름, 이메일, 가입일자로 각각 검색하는 쿼리가 자주 실행됩니다. 각 컬럼에 개별 인덱스를 생성했지만, WHERE 절에 여러 조건이 AND로 결합된 쿼리의 성능이 기대보다 낮습니다. 복합 인덱스(Composite Index) 설계 시 고려해야 할 컬럼 순서 결정 원칙과, 인덱스가 실제로 사용되는지 확인하는 방법을 설명해주세요.
카디널리티(Cardinality)와 선택도(Selectivity) 개념을 생각해보고, 실행 계획을 어떻게 확인할 수 있는지 고려해보세요.
복합 인덱스의 컬럼 순서는 카디널리티가 높은(중복이 적은) 컬럼을 앞에 배치하는 것이 일반적이며, 쿼리의 WHERE 절에서 등호(=) 조건으로 사용되는 컬럼을 범위 조건보다 앞에 두어야 합니다. 예를 들어 이메일(고유값)은 앞에, 가입일자(범위 검색)는 뒤에 배치합니다. 인덱스 사용 여부는 EXPLAIN 또는 EXPLAIN ANALYZE 명령으로 실행 계획을 확인하여 Index Scan이 발생하는지, Full Table Scan이 발생하는지 검증할 수 있습니다. 또한 인덱스 힌트를 사용하여 옵티마이저의 선택을 강제하거나, 실제 쿼리 실행 시간과 I/O 비용을 프로파일링하여 성능을 측정해야 합니다. 복합 인덱스는 leftmost prefix 규칙을 따르므로, 첫 번째 컬럼 없이 두 번째 컬럼만 사용하는 쿼리에서는 인덱스가 활용되지 않는다는 점도 고려해야 합니다.
- • 카디널리티가 높은 컬럼을 앞에 배치
- • 등호 조건 컬럼을 범위 조건보다 앞에 배치
- • EXPLAIN으로 실행 계획 확인
- • Leftmost prefix 규칙 이해
전자상거래 사이트에서 상품 검색 시 카테고리, 가격대, 등록일 등 다중 필터링 조건을 처리할 때 복합 인덱스 설계가 필수적입니다.
커버링 인덱스(Covering Index)란 무엇이며, 어떤 경우에 성능 향상 효과가 크고, 어떤 단점이 있는지 설명해주세요.
Q. 온라인 쇼핑몰에서 동일한 상품을 여러 사용자가 동시에 구매하려 할 때, 재고 차감 로직에서 Lost Update 문제가 발생했습니다. READ COMMITTED 격리 수준을 사용 중이며, 단순히 SELECT로 재고를 읽고 UPDATE하는 방식입니다. 이 문제를 해결하기 위한 비관적 락(Pessimistic Lock)과 낙관적 락(Optimistic Lock) 방식을 각각 설명하고, 트래픽 패턴에 따라 어떤 방식을 선택해야 하는지 트레이드오프를 분석해주세요.
FOR UPDATE 구문과 버전 컬럼을 활용한 방법을 생각해보고, 충돌 빈도와 재시도 비용을 고려해보세요.
비관적 락은 SELECT FOR UPDATE 구문을 사용하여 트랜잭션이 시작될 때 해당 행에 배타적 락을 걸어 다른 트랜잭션의 접근을 차단하는 방식으로, 데이터 일관성을 보장하지만 동시성이 낮아지고 데드락 위험이 있습니다. 낙관적 락은 버전 컬럼(version)이나 타임스탬프를 사용하여 UPDATE 시점에 버전을 비교해 충돌을 감지하고, 충돌 발생 시 트랜잭션을 롤백하고 재시도하는 방식으로, 동시성은 높지만 충돌이 빈번하면 재시도 비용이 증가합니다. 트래픽이 높고 충돌이 빈번한 인기 상품의 경우 비관적 락이 적합하며, 충돌이 드문 일반 상품은 낙관적 락으로 높은 처리량을 확보하는 것이 유리합니다. 또한 데이터베이스 수준의 락 외에도 Redis 같은 분산 락을 활용하거나, 재고를 미리 예약하는 방식의 아키텍처 변경도 고려할 수 있습니다. SERIALIZABLE 격리 수준으로 변경하면 Lost Update는 방지되지만 성능 저하가 크므로 실무에서는 적절한 락 전략 선택이 중요합니다.
- • 비관적 락: SELECT FOR UPDATE로 배타적 락 획득
- • 낙관적 락: 버전 컬럼으로 충돌 감지 및 재시도
- • 충돌 빈도에 따른 전략 선택
- • 데드락 위험과 재시도 비용 고려
한정 수량 이벤트 상품 판매나 좌석 예약 시스템에서 동시 접근으로 인한 재고 오버셀링을 방지하기 위해 락 전략이 필수적입니다.
데드락이 발생하는 구체적인 시나리오를 설명하고, 데드락을 예방하거나 탐지했을 때 애플리케이션 레벨에서 어떻게 대응해야 하는지 설명해주세요.
Q. 주문 테이블(orders)과 주문 상세 테이블(order_items)을 JOIN하여 월별 매출 집계를 구하는 쿼리가 있습니다. 데이터가 수백만 건으로 증가하면서 쿼리 실행 시간이 30초 이상 소요되고 있습니다. Slow Query Log에서 이 쿼리를 발견했을 때, 쿼리를 분석하고 최적화하는 단계별 접근 방법과, 인덱스 외에 고려할 수 있는 다른 최적화 기법들을 설명해주세요.
실행 계획 분석, 조인 방식, 집계 전략, 그리고 데이터 모델링 관점에서 생각해보세요.
먼저 EXPLAIN ANALYZE로 실행 계획을 확인하여 Full Table Scan, Nested Loop Join 등 비효율적인 부분을 식별하고, 조인 키와 WHERE 절 컬럼에 적절한 인덱스가 있는지 확인합니다. 조인 순서를 최적화하여 작은 결과셋을 먼저 생성하도록 하고, 필요시 STRAIGHT_JOIN 힌트로 조인 순서를 명시할 수 있습니다. 월별 집계처럼 자주 조회되는 통계 데이터는 materialized view나 summary table을 생성하여 미리 집계해두고, 배치 작업으로 주기적으로 갱신하는 방식으로 실시간 쿼리 부하를 줄일 수 있습니다. 파티셔닝을 활용하여 날짜 기준으로 테이블을 분할하면 필요한 파티션만 스캔하여 I/O를 대폭 줄일 수 있습니다. 또한 SELECT 절에서 불필요한 컬럼을 제거하고, GROUP BY 전에 WHERE 절로 데이터를 충분히 필터링하며, 서브쿼리 대신 JOIN을 사용하는 등 쿼리 구조 자체를 개선하는 것도 중요합니다.
- • EXPLAIN ANALYZE로 실행 계획 분석
- • 조인 키와 필터 컬럼에 인덱스 확인
- • Summary table이나 materialized view 활용
- • 파티셔닝으로 스캔 범위 축소
대시보드나 리포트 기능에서 대용량 데이터를 집계할 때 쿼리 성능 저하로 인한 사용자 경험 악화를 방지하기 위해 쿼리 튜닝이 필수적입니다.
파티셔닝 전략 중 Range Partitioning과 Hash Partitioning의 차이를 설명하고, 각각 어떤 쿼리 패턴에 유리한지 비교해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!