데이터베이스 주니어 기술면접
새 면접Q. 데이터베이스 인덱스란 무엇이며, 인덱스를 사용하는 이유는 무엇인가요?
책의 색인과 비교해서 생각해보세요.
인덱스는 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조입니다. 책의 색인처럼 특정 값을 빠르게 찾을 수 있도록 별도의 정렬된 구조를 유지합니다. 인덱스가 없으면 테이블 전체를 스캔(Full Table Scan)해야 하지만, 인덱스가 있으면 필요한 데이터만 빠르게 찾을 수 있습니다. 주로 B-Tree, Hash 등의 자료구조로 구현되며, WHERE 절이나 JOIN 조건에서 자주 사용되는 컬럼에 생성합니다. 다만 인덱스는 저장 공간을 추가로 사용하고, INSERT/UPDATE/DELETE 시 성능 저하를 일으킬 수 있습니다.
- • 검색 속도 향상을 위한 자료구조
- • Full Table Scan 방지
- • 쓰기 성능 저하 트레이드오프
사용자 검색 기능에서 이메일이나 이름으로 빠르게 조회하기 위해 해당 컬럼에 인덱스를 생성합니다.
인덱스를 생성하면 오히려 성능이 나빠지는 경우는 언제인가요?
Q. 트랜잭션의 ACID 속성에 대해 설명해주세요.
각 알파벳이 의미하는 속성과 그 목적을 생각해보세요.
ACID는 트랜잭션의 안전성을 보장하는 네 가지 속성입니다. Atomicity(원자성)는 트랜잭션의 모든 작업이 전부 성공하거나 전부 실패해야 함을 의미합니다. Consistency(일관성)는 트랜잭션 전후로 데이터베이스가 일관된 상태를 유지해야 함을 뜻합니다. Isolation(격리성)은 동시에 실행되는 트랜잭션들이 서로 영향을 주지 않도록 격리되어야 함을 의미합니다. Durability(지속성)는 커밋된 트랜잭션의 결과가 영구적으로 저장되어야 함을 보장합니다.
- • Atomicity: 전부 성공 또는 전부 실패
- • Consistency: 일관된 상태 유지
- • Isolation: 트랜잭션 간 격리
- • Durability: 영구적 저장
결제 시스템에서 계좌 이체 시 출금과 입금이 모두 성공하거나 모두 실패해야 하는 상황에 적용됩니다.
Isolation 속성을 완벽하게 보장하면 어떤 문제가 발생할 수 있나요?
Q. 트랜잭션 격리 수준(Isolation Level) 4가지를 설명하고, 각각 어떤 문제를 해결하는지 말씀해주세요.
격리 수준이 높아질수록 동시성은 낮아지고 일관성은 높아집니다.
READ UNCOMMITTED는 커밋되지 않은 데이터도 읽을 수 있어 Dirty Read가 발생하지만 성능이 가장 좋습니다. READ COMMITTED는 커밋된 데이터만 읽어 Dirty Read를 방지하지만 Non-Repeatable Read가 발생할 수 있습니다. REPEATABLE READ는 트랜잭션 내에서 같은 데이터를 여러 번 읽어도 같은 결과를 보장하지만 Phantom Read가 발생할 수 있습니다. SERIALIZABLE은 가장 엄격한 격리 수준으로 모든 문제를 방지하지만 동시성이 가장 낮습니다. 대부분의 데이터베이스는 READ COMMITTED를 기본값으로 사용하며, MySQL InnoDB는 REPEATABLE READ를 기본으로 사용합니다.
- • 격리 수준이 높을수록 일관성 증가, 동시성 감소
- • READ COMMITTED가 일반적인 기본값
- • 각 수준별로 방지하는 문제가 다름
재고 관리 시스템에서 동시 주문 처리 시 데이터 정합성과 성능을 고려해 적절한 격리 수준을 선택합니다.
MySQL InnoDB에서 REPEATABLE READ 수준에서도 Phantom Read가 발생하지 않는 이유는 무엇인가요?
Q. 데이터베이스에서 Shared Lock과 Exclusive Lock의 차이점을 설명해주세요.
읽기와 쓰기 작업에서 각각 어떤 락이 사용되는지 생각해보세요.
Shared Lock(공유 락, S Lock)은 읽기 작업에 사용되며, 여러 트랜잭션이 동시에 같은 데이터에 대해 Shared Lock을 획득할 수 있습니다. Exclusive Lock(배타 락, X Lock)은 쓰기 작업에 사용되며, 한 트랜잭션만 획득할 수 있고 다른 트랜잭션은 Shared Lock도 Exclusive Lock도 획득할 수 없습니다. Shared Lock이 걸린 데이터는 다른 트랜잭션이 읽을 수 있지만 수정할 수 없으며, Exclusive Lock이 걸린 데이터는 다른 트랜잭션이 읽거나 수정할 수 없습니다. 이를 통해 데이터의 일관성을 유지하면서 동시성을 제어합니다.
- • Shared Lock: 읽기 작업, 동시 획득 가능
- • Exclusive Lock: 쓰기 작업, 독점적 획득
- • 락 호환성 규칙
좌석 예매 시스템에서 여러 사용자가 동시에 좌석 정보를 조회하고 예매할 때 락을 사용해 이중 예매를 방지합니다.
데드락(Deadlock)은 어떤 상황에서 발생하며, 어떻게 해결할 수 있나요?
Q. SELECT 쿼리의 성능이 느릴 때 어떤 방법으로 원인을 파악하고 개선할 수 있나요?
실행 계획을 확인하는 방법부터 시작해보세요.
먼저 EXPLAIN 명령어를 사용해 쿼리의 실행 계획을 확인하여 Full Table Scan이 발생하는지, 인덱스가 사용되는지 파악합니다. 인덱스가 없거나 사용되지 않는다면 적절한 컬럼에 인덱스를 추가하거나 쿼리를 수정해 인덱스를 활용하도록 합니다. SELECT 절에서 필요한 컬럼만 조회하고 불필요한 JOIN을 제거하며, WHERE 절의 조건을 최적화합니다. 함수나 연산이 인덱스 컬럼에 적용되면 인덱스를 사용할 수 없으므로 쿼리를 재작성합니다. 필요하다면 쿼리를 분리하거나 캐싱을 적용하고, 테이블 통계 정보를 업데이트하여 옵티마이저가 올바른 실행 계획을 선택하도록 합니다.
- • EXPLAIN으로 실행 계획 확인
- • 인덱스 추가 및 활용
- • 쿼리 구조 최적화
- • 통계 정보 업데이트
게시판 목록 조회 API가 느려질 때 EXPLAIN으로 분석하여 날짜 컬럼에 인덱스를 추가해 성능을 개선합니다.
인덱스가 있는데도 옵티마이저가 인덱스를 사용하지 않는 경우는 언제인가요?
Q. 정규화(Normalization)가 무엇이며, 왜 필요한가요?
데이터 중복과 이상 현상의 관계를 생각해보세요.
정규화는 데이터베이스 설계 시 데이터의 중복을 최소화하고 무결성을 유지하기 위해 테이블을 분해하는 과정입니다. 중복된 데이터가 여러 곳에 저장되면 삽입 이상, 갱신 이상, 삭제 이상 등의 문제가 발생할 수 있습니다. 정규화를 통해 각 데이터를 한 곳에만 저장하고 관계로 연결함으로써 데이터 일관성을 보장합니다. 일반적으로 1NF, 2NF, 3NF, BCNF 등의 단계로 진행되며, 실무에서는 3NF까지 적용하는 것이 일반적입니다. 다만 과도한 정규화는 JOIN 연산을 증가시켜 성능 저하를 일으킬 수 있어 적절한 균형이 필요합니다.
- • 데이터 중복 최소화
- • 삽입/갱신/삭제 이상 방지
- • 데이터 무결성 보장
사용자와 주문 정보를 설계할 때 사용자 정보를 별도 테이블로 분리해 중복을 제거하고 일관성을 유지합니다.
반정규화(Denormalization)는 언제 필요하며, 어떤 경우에 사용하나요?
Q. 복합 인덱스(Composite Index)를 생성할 때 컬럼 순서가 중요한 이유를 설명해주세요.
인덱스가 왼쪽부터 순차적으로 사용된다는 점을 생각해보세요.
복합 인덱스는 여러 컬럼을 조합한 인덱스로, 컬럼 순서에 따라 인덱스 활용도가 달라집니다. 인덱스는 왼쪽 컬럼부터 순차적으로 사용되므로, WHERE 절에서 첫 번째 컬럼이 없으면 인덱스를 사용할 수 없습니다. 예를 들어 (A, B, C) 순서의 복합 인덱스는 A, (A, B), (A, B, C) 조건에서는 사용되지만 B나 C만 단독으로 사용하는 조건에서는 활용되지 않습니다. 따라서 카디널리티가 높고 자주 사용되는 컬럼을 앞쪽에 배치하는 것이 일반적입니다. 또한 등호(=) 조건이 범위 조건보다 앞에 오도록 순서를 정하는 것이 효율적입니다.
- • 왼쪽 컬럼부터 순차적으로 사용
- • 첫 번째 컬럼이 없으면 인덱스 미사용
- • 카디널리티와 사용 빈도 고려
게시판 검색에서 카테고리와 작성일로 조회할 때 (category_id, created_at) 순서로 복합 인덱스를 생성합니다.
인덱스 스캔 방식 중 Index Scan과 Index Seek의 차이는 무엇인가요?
Q. 서비스 운영 중 결제 처리 도중 서버가 재시작되었습니다. 트랜잭션의 어떤 속성이 데이터 손실을 방지하며, 데이터베이스는 어떻게 이를 보장하나요?
ACID 중 커밋된 데이터의 영구성과 관련된 속성을 생각해보세요.
Durability(지속성) 속성이 커밋된 트랜잭션의 데이터 손실을 방지합니다. 데이터베이스는 WAL(Write-Ahead Logging) 방식을 사용하여 실제 데이터를 디스크에 쓰기 전에 트랜잭션 로그를 먼저 기록합니다. 커밋 시점에는 로그만 디스크에 동기화하고, 실제 데이터 페이지는 나중에 백그라운드로 기록됩니다. 서버가 비정상 종료되더라도 재시작 시 트랜잭션 로그를 읽어 커밋된 트랜잭션은 Redo하고 커밋되지 않은 트랜잭션은 Undo하여 일관성을 복구합니다. 이를 통해 시스템 장애 상황에서도 데이터 무결성을 보장할 수 있습니다.
- • Durability 속성이 영구성 보장
- • WAL(Write-Ahead Logging) 방식
- • Redo/Undo를 통한 복구
결제 완료 후 서버 장애가 발생해도 커밋된 결제 내역은 트랜잭션 로그를 통해 복구되어 손실되지 않습니다.
체크포인트(Checkpoint)는 무엇이며, 왜 필요한가요?
Q. 1:N 관계와 N:M 관계를 데이터베이스에서 어떻게 구현하나요? 각각의 예시를 들어 설명해주세요.
N:M 관계는 중간 테이블이 필요합니다.
1:N 관계는 한쪽 테이블의 기본키를 다른 테이블의 외래키로 참조하여 구현합니다. 예를 들어 사용자와 게시글의 관계에서 게시글 테이블에 user_id 외래키를 두어 한 사용자가 여러 게시글을 작성할 수 있도록 합니다. N:M 관계는 중간 테이블(Junction Table)을 생성하여 양쪽 테이블의 기본키를 외래키로 가지는 방식으로 구현합니다. 학생과 수업의 관계에서 수강신청 테이블을 만들어 student_id와 course_id를 외래키로 가지며, 한 학생이 여러 수업을 듣고 한 수업에 여러 학생이 참여할 수 있습니다. 중간 테이블에는 추가 정보(수강 신청일, 성적 등)도 함께 저장할 수 있습니다.
- • 1:N은 외래키로 직접 참조
- • N:M은 중간 테이블 필요
- • 중간 테이블에 추가 정보 저장 가능
쇼핑몰에서 상품과 카테고리의 N:M 관계를 구현할 때 product_category 중간 테이블을 사용합니다.
자기 참조 관계(Self-Referencing)는 어떤 경우에 사용되며, 어떻게 구현하나요?
Q. 대용량 테이블에서 페이징 처리 시 OFFSET이 커질수록 성능이 저하되는 이유와 이를 개선하는 방법을 설명해주세요.
OFFSET 방식이 내부적으로 어떻게 동작하는지 생각해보세요.
OFFSET 방식은 건너뛸 행들도 모두 읽어야 하기 때문에 OFFSET 값이 커질수록 성능이 저하됩니다. 예를 들어 OFFSET 10000 LIMIT 10은 10010개의 행을 읽은 후 처음 10000개를 버리고 10개만 반환합니다. 이를 개선하기 위해 커서 기반 페이징(Cursor-based Pagination)을 사용할 수 있으며, 마지막으로 조회한 행의 ID나 정렬 기준 값을 기억해두고 WHERE 절에서 그 이후 데이터만 조회합니다. 예를 들어 WHERE id > last_id ORDER BY id LIMIT 10 형태로 쿼리하면 인덱스를 효율적으로 활용할 수 있습니다. 이 방식은 특정 페이지로 직접 이동할 수 없다는 단점이 있지만, 무한 스크롤 방식의 UI에서는 매우 효과적입니다.
- • OFFSET은 건너뛸 행도 모두 읽음
- • 커서 기반 페이징으로 개선
- • WHERE 조건으로 이전 데이터 필터링
SNS 피드나 상품 목록에서 무한 스크롤 구현 시 마지막 조회 ID를 기준으로 다음 데이터를 가져옵니다.
커서 기반 페이징에서 정렬 기준이 여러 개일 때는 어떻게 처리해야 하나요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!