PHP 주니어 데이터베이스 기술면접
새 면접Q. 회원 테이블(users)에 email 컬럼이 있고, 로그인 시 WHERE email = ? 쿼리가 자주 실행됩니다. 이 컬럼에 인덱스를 생성할 때 UNIQUE INDEX와 일반 INDEX 중 어떤 것을 선택해야 하는지 설명하고, 각각의 차이점과 선택 기준을 말씀해주세요.
이메일이라는 데이터의 특성과 비즈니스 요구사항을 함께 고려해보세요.
회원 테이블의 email 컬럼에는 UNIQUE INDEX를 사용해야 합니다. UNIQUE INDEX는 중복된 값을 허용하지 않으면서 빠른 검색을 제공하고, 일반 INDEX는 중복 값을 허용하며 검색 속도만 향상시킵니다. 이메일은 로그인 식별자로 사용되므로 중복되면 안 되며, UNIQUE INDEX를 사용하면 데이터베이스 레벨에서 중복을 방지할 수 있습니다. 또한 UNIQUE INDEX는 일반 INDEX보다 약간 더 빠른 검색 성능을 제공합니다. 비즈니스 로직에서 중복 체크를 하더라도 동시성 이슈로 중복이 발생할 수 있으므로 데이터베이스 제약조건으로 보장하는 것이 안전합니다.
- • UNIQUE INDEX는 중복 값을 허용하지 않고, 일반 INDEX는 중복 허용
- • 이메일은 회원 식별자이므로 중복되면 안 됨
- • 데이터베이스 레벨에서 중복을 방지하여 동시성 이슈 해결
- • UNIQUE INDEX가 일반 INDEX보다 약간 더 빠른 검색 성능 제공
회원가입 시 이메일 중복 검사와 로그인 처리에서 UNIQUE INDEX를 통해 데이터 무결성과 성능을 동시에 확보합니다.
만약 이메일 외에 휴대폰 번호로도 로그인이 가능한 시스템이라면, 두 컬럼에 어떻게 인덱스를 설계하시겠습니까?
Q. 게시글 테이블에서 WHERE category_id = ? AND status = 'published' ORDER BY created_at DESC 쿼리가 자주 실행됩니다. 이 쿼리를 최적화하기 위한 복합 인덱스(Composite Index)를 설계할 때, 컬럼의 순서를 어떻게 정해야 하는지 설명하고 그 이유를 말씀해주세요.
WHERE 절의 조건 컬럼들과 ORDER BY 컬럼의 우선순위를 고려해보세요.
복합 인덱스는 (category_id, status, created_at) 순서로 생성해야 합니다. 인덱스 컬럼 순서는 카디널리티(고유값의 수)가 높은 컬럼을 앞에 배치하는 것이 일반적이지만, WHERE 절에서 등호(=) 조건으로 사용되는 컬럼을 먼저 배치해야 합니다. category_id와 status로 데이터를 먼저 필터링한 후, created_at으로 정렬하면 인덱스만으로 쿼리를 처리할 수 있습니다(커버링 인덱스). 만약 created_at을 앞에 두면 범위 검색이 되어 뒤의 컬럼들이 인덱스로 활용되지 못합니다. 실제로는 EXPLAIN 명령어로 실행 계획을 확인하여 최적의 순서를 검증해야 합니다.
- • WHERE 절의 등호 조건 컬럼을 앞에 배치
- • ORDER BY 컬럼은 마지막에 배치
- • 커버링 인덱스로 만들어 테이블 접근 없이 인덱스만으로 처리
- • EXPLAIN으로 실행 계획 검증 필요
게시판 목록 조회 API에서 카테고리별 공개 게시글을 최신순으로 보여줄 때 복합 인덱스로 쿼리 성능을 대폭 개선합니다.
만약 이 쿼리에서 ORDER BY created_at DESC, view_count DESC처럼 정렬 컬럼이 2개라면 인덱스 설계가 어떻게 달라지나요?
Q. MySQL InnoDB에서 제공하는 4가지 트랜잭션 격리 수준(Isolation Level) 중 READ COMMITTED와 REPEATABLE READ의 차이점을 설명하고, MySQL의 기본 격리 수준은 무엇인지 말씀해주세요.
같은 트랜잭션 내에서 같은 SELECT 쿼리를 두 번 실행했을 때 결과가 어떻게 다른지 생각해보세요.
READ COMMITTED는 커밋된 데이터만 읽을 수 있지만, 같은 트랜잭션 내에서 같은 쿼리를 두 번 실행하면 다른 결과가 나올 수 있습니다(Non-Repeatable Read). REPEATABLE READ는 트랜잭션 시작 시점의 스냅샷을 기준으로 데이터를 읽어 같은 쿼리를 여러 번 실행해도 동일한 결과를 보장합니다. MySQL InnoDB의 기본 격리 수준은 REPEATABLE READ이며, MVCC(Multi-Version Concurrency Control) 기술로 구현됩니다. REPEATABLE READ는 일관성 있는 읽기를 제공하지만, Phantom Read가 발생할 수 있습니다. 실무에서는 대부분 기본 격리 수준을 사용하며, 특별한 요구사항이 있을 때만 변경합니다.
- • READ COMMITTED는 Non-Repeatable Read 발생 가능
- • REPEATABLE READ는 트랜잭션 내 일관된 읽기 보장
- • MySQL InnoDB 기본값은 REPEATABLE READ
- • MVCC로 구현되며 Phantom Read 가능성 존재
결제 처리나 재고 관리 시스템에서 트랜잭션 격리 수준을 이해하고 설정해야 데이터 정합성 문제를 예방할 수 있습니다.
Phantom Read가 무엇인지 설명하고, 이를 방지하려면 어떤 격리 수준을 사용해야 하나요?
Q. 상품 주문 시스템에서 재고 차감 로직을 구현할 때, SELECT로 재고를 확인한 후 UPDATE로 차감하는 방식은 동시성 문제가 발생할 수 있습니다. 이를 해결하기 위한 FOR UPDATE 락의 동작 원리와 사용 방법을 설명해주세요.
SELECT ... FOR UPDATE 구문이 트랜잭션 내에서 어떤 락을 걸고, 다른 트랜잭션에 어떤 영향을 주는지 생각해보세요.
FOR UPDATE는 SELECT 쿼리에 배타적 락(Exclusive Lock)을 걸어 다른 트랜잭션이 해당 행을 수정하거나 FOR UPDATE로 읽지 못하게 합니다. 사용 방법은 트랜잭션 내에서 SELECT stock FROM products WHERE id = ? FOR UPDATE로 재고를 조회하고, 재고가 충분하면 UPDATE로 차감하는 방식입니다. 락은 트랜잭션이 커밋되거나 롤백될 때까지 유지되어 동시에 여러 주문이 들어와도 순차적으로 처리됩니다. 일반 SELECT는 다른 트랜잭션에서도 가능하지만, FOR UPDATE나 UPDATE는 대기하게 됩니다. 단점은 락 대기 시간이 길어질 수 있으므로 트랜잭션을 최대한 짧게 유지해야 합니다.
- • FOR UPDATE는 배타적 락을 걸어 동시 수정 방지
- • 트랜잭션 내에서 사용하며 커밋/롤백 시 락 해제
- • 다른 트랜잭션의 FOR UPDATE와 UPDATE는 대기
- • 트랜잭션을 짧게 유지하여 락 대기 시간 최소화
이커머스에서 한정 수량 상품 주문 시 재고 차감 로직에 FOR UPDATE를 사용하여 overselling을 방지합니다.
FOR UPDATE 대신 낙관적 락(Optimistic Lock)을 사용하는 방법도 있습니다. 두 방식의 차이점과 각각 어떤 상황에 적합한지 설명해주세요.
Q. 게시글 목록 조회 시 작성자 정보를 함께 보여주기 위해 posts 테이블과 users 테이블을 조인하는 쿼리가 있습니다. N+1 쿼리 문제가 무엇인지 설명하고, PHP에서 이를 해결하는 방법을 말씀해주세요.
반복문 안에서 개별 쿼리를 실행하는 것과 한 번에 JOIN하거나 IN 절을 사용하는 것의 차이를 생각해보세요.
N+1 문제는 게시글 목록을 조회하는 1번의 쿼리 후, 각 게시글의 작성자 정보를 가져오기 위해 N번의 추가 쿼리가 실행되는 문제입니다. 예를 들어 게시글 100개를 조회하면 총 101번의 쿼리가 실행되어 성능이 크게 저하됩니다. 해결 방법은 첫째, JOIN을 사용하여 한 번의 쿼리로 모든 데이터를 가져오는 것입니다. 둘째, 게시글을 먼저 조회한 후 작성자 ID 목록을 추출하여 WHERE user_id IN (?) 쿼리로 한 번에 가져오는 방법입니다. Laravel 같은 ORM에서는 Eager Loading 기능으로 자동으로 최적화할 수 있습니다. 쿼리 수를 줄이면 데이터베이스 부하와 네트워크 오버헤드가 감소합니다.
- • N+1 문제는 반복문 내 개별 쿼리 실행으로 발생
- • JOIN으로 한 번에 조회하거나 IN 절로 일괄 조회
- • ORM의 Eager Loading 기능 활용
- • 쿼리 수 감소로 성능 개선
게시판, SNS 피드, 댓글 목록 등 관계된 데이터를 함께 보여주는 모든 화면에서 N+1 문제를 해결해야 성능이 유지됩니다.
JOIN을 사용할 때 INNER JOIN과 LEFT JOIN의 차이점과 각각 어떤 상황에서 사용해야 하는지 설명해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!