MySQL 미드레벨 기술면접
새 면접Q. MySQL에서 DISTINCT와 GROUP BY를 사용하여 중복을 제거할 수 있습니다. 두 방식의 내부 동작 원리와 성능 차이를 설명하고, 어떤 상황에서 어느 것을 선택해야 하는지 실무 관점에서 설명해주세요.
옵티마이저가 두 방식을 처리하는 방법과 집계 함수 사용 여부를 고려해보세요.
DISTINCT는 결과 집합에서 중복 행을 제거하는 단순한 연산이며, GROUP BY는 그룹화 후 집계 연산을 수행합니다. MySQL 옵티마이저는 집계 함수가 없는 GROUP BY를 DISTINCT와 동일하게 처리하는 경우가 많습니다. DISTINCT는 단순 중복 제거만 필요할 때 사용하며, 가독성이 더 좋습니다. GROUP BY는 COUNT, SUM 등 집계 함수와 함께 사용하거나 HAVING 절로 필터링이 필요할 때 선택합니다. 실행 계획을 확인하면 둘 다 임시 테이블이나 정렬을 사용할 수 있으며, 인덱스가 있다면 성능이 크게 향상됩니다.
- • DISTINCT는 중복 제거 전용, GROUP BY는 그룹화 및 집계
- • 옵티마이저가 동일하게 처리하는 경우 존재
- • 집계 함수 필요 여부로 선택 기준 결정
대량의 로그 데이터에서 고유 사용자 수를 집계하거나 중복 없는 카테고리 목록을 조회할 때 사용됩니다.
GROUP BY에서 집계 함수 없이 사용할 때 발생할 수 있는 SQL_MODE 관련 문제와 ONLY_FULL_GROUP_BY 설정에 대해 설명해주세요.
Q. 시계열 데이터(Time Series Data)를 MySQL에 저장할 때 단일 테이블 구조와 시간 기반 파티셔닝 구조의 장단점을 비교하고, IoT 센서 데이터처럼 초당 수천 건의 데이터가 들어오는 상황에서 어떤 설계가 적합한지 설명해주세요.
쿼리 패턴, 데이터 보관 정책, 인덱스 크기 증가를 고려해보세요.
단일 테이블은 구조가 단순하지만 시간이 지날수록 테이블 크기가 커져 인덱스 효율이 떨어지고 쿼리 성능이 저하됩니다. 시간 기반 파티셔닝은 최근 데이터 조회 시 특정 파티션만 스캔하여 성능이 우수하며, 오래된 데이터를 파티션 단위로 삭제할 수 있어 운영이 편리합니다. IoT 센서 데이터처럼 대량 삽입이 발생하는 경우 파티셔닝이 적합하며, 일별 또는 월별 파티션으로 나누는 것이 일반적입니다. 단, 파티션 키를 WHERE 절에 포함해야 파티션 프루닝 효과를 얻을 수 있습니다. 추가로 오래된 데이터는 집계 테이블로 요약하여 원본 데이터를 삭제하는 전략도 함께 고려해야 합니다.
- • 단일 테이블은 시간 경과에 따라 성능 저하
- • 파티셔닝은 최근 데이터 조회와 오래된 데이터 삭제에 유리
- • 파티션 키를 쿼리에 포함해야 효과 발생
IoT 센서 데이터, 애플리케이션 로그, 모니터링 메트릭 등 시간 기반으로 계속 증가하는 데이터를 관리할 때 사용됩니다.
파티션 개수가 너무 많아지면 발생하는 문제와 적정 파티션 개수를 결정하는 기준을 설명해주세요.
Q. 분산 트랜잭션 환경에서 Two-Phase Commit(2PC) 프로토콜의 동작 원리를 설명하고, MySQL에서 XA 트랜잭션을 사용할 때의 성능 오버헤드와 실무에서 2PC 대신 Saga 패턴을 선택하는 이유를 설명해주세요.
Prepare와 Commit 단계, 코디네이터 장애 상황, 보상 트랜잭션 개념을 생각해보세요.
2PC는 Prepare 단계에서 모든 참여자가 커밋 가능 여부를 확인하고, Commit 단계에서 실제 커밋을 수행하는 두 단계로 구성됩니다. MySQL의 XA 트랜잭션은 2PC를 지원하지만, 추가 로그 기록과 락 유지 시간 증가로 성능 오버헤드가 큽니다. 코디네이터 장애 시 참여자들이 블로킹 상태에 빠질 수 있는 위험이 있습니다. Saga 패턴은 각 서비스가 로컬 트랜잭션을 수행하고 실패 시 보상 트랜잭션으로 롤백하는 방식으로, 장시간 락을 유지하지 않아 성능과 가용성이 우수합니다. 마이크로서비스 환경에서는 완벽한 일관성 대신 최종 일관성을 받아들이고 Saga 패턴을 선택하는 것이 일반적입니다.
- • 2PC는 Prepare와 Commit 두 단계로 동작
- • XA 트랜잭션은 성능 오버헤드와 블로킹 위험 존재
- • Saga 패턴은 보상 트랜잭션으로 최종 일관성 보장
주문 서비스와 결제 서비스가 분리된 마이크로서비스 환경에서 트랜잭션 일관성을 유지할 때 사용됩니다.
Saga 패턴의 Choreography 방식과 Orchestration 방식의 차이점과 각각의 장단점을 설명해주세요.
Q. MySQL에서 COUNT(*), COUNT(1), COUNT(column) 간의 차이점과 성능 차이를 설명하고, 대용량 테이블에서 전체 행 개수를 빠르게 조회하기 위한 실무 최적화 전략을 설명해주세요.
NULL 처리 방식, InnoDB의 통계 정보, 근사값 사용 가능성을 고려해보세요.
COUNT(*)와 COUNT(1)은 동일하게 동작하며 모든 행을 카운트합니다. COUNT(column)은 해당 컬럼이 NULL이 아닌 행만 카운트합니다. InnoDB는 MVCC로 인해 정확한 행 개수를 저장하지 않아 전체 테이블 스캔이 필요하므로 대용량 테이블에서는 매우 느립니다. 실무에서는 INFORMATION_SCHEMA의 통계 정보를 활용하여 근사값을 사용하거나, 별도의 카운터 테이블을 두고 INSERT/DELETE 시 증감시키는 방법을 사용합니다. WHERE 조건이 있다면 커버링 인덱스를 활용하여 인덱스만 스캔하도록 최적화할 수 있습니다. 페이지네이션에서 정확한 전체 개수가 불필요하다면 'more' 방식으로 대체하는 것도 좋은 전략입니다.
- • COUNT(*)와 COUNT(1)은 동일, COUNT(column)은 NULL 제외
- • InnoDB는 정확한 행 개수를 저장하지 않음
- • 카운터 테이블이나 근사값 사용이 실무 전략
게시판의 전체 게시물 수나 상품의 총 개수를 표시할 때 빠른 조회를 위해 최적화가 필요합니다.
카운터 테이블을 사용할 때 동시성 문제를 해결하기 위한 샤딩 전략을 설명해주세요.
Q. MySQL에서 Full-Text Index의 동작 원리와 일반 B-Tree 인덱스와의 차이점을 설명하고, LIKE '%keyword%' 검색 대신 Full-Text Index를 사용할 때의 장단점과 적용 시 고려사항을 설명해주세요.
역색인 구조, 자연어 검색 모드, 최소 단어 길이 설정을 생각해보세요.
Full-Text Index는 역색인(Inverted Index) 구조로 단어와 해당 단어가 포함된 문서를 매핑하여 텍스트 검색에 특화되어 있습니다. B-Tree 인덱스는 LIKE '%keyword%'처럼 중간 일치 검색을 지원하지 못하지만, Full-Text Index는 자연어 검색이 가능합니다. 장점은 대용량 텍스트 검색 성능이 우수하고 관련도 점수를 제공한다는 점이며, 단점은 인덱스 크기가 크고 CJK 언어는 n-gram 파서가 필요하다는 점입니다. ft_min_word_len 등 파라미터 설정이 필요하며, 불용어(stopword) 처리를 고려해야 합니다. 실시간 검색보다는 게시물이나 상품 설명처럼 업데이트가 상대적으로 적은 데이터에 적합합니다.
- • Full-Text Index는 역색인 구조로 텍스트 검색 특화
- • 중간 일치 검색과 자연어 검색 가능
- • 인덱스 크기가 크고 언어별 파서 설정 필요
블로그 게시물 검색, 상품 설명 검색, FAQ 검색 등 텍스트 기반 검색 기능을 구현할 때 사용됩니다.
Elasticsearch 같은 전용 검색 엔진과 MySQL Full-Text Index를 비교하고, 어떤 상황에서 각각을 선택해야 하는지 설명해주세요.
Q. 프로덕션 환경에서 특정 사용자의 요청만 타임아웃이 발생하고 다른 사용자는 정상 동작하는 현상이 발생했습니다. MySQL 쿼리 자체는 EXPLAIN 결과 문제가 없어 보이는데, 이런 사용자별 편차가 발생하는 원인을 진단하는 방법과 가능한 원인들을 설명해주세요.
데이터 분포, 락 대기, 커넥션 상태, 캐시 히트율을 생각해보세요.
사용자별로 데이터 양이 크게 다를 경우 옵티마이저가 동일한 쿼리에 대해 다른 실행 계획을 선택할 수 있습니다. SHOW PROCESSLIST로 해당 사용자 세션이 락 대기 중인지 확인하고, 다른 트랜잭션이 해당 사용자의 데이터에 락을 걸고 있는지 확인해야 합니다. 특정 사용자가 대량의 연관 데이터를 가지고 있어 조인 비용이 급증하는 경우도 있습니다. 버퍼 풀 캐시 히트율 차이로 인해 특정 사용자 데이터가 디스크 I/O를 유발할 수도 있습니다. 실제 문제 사용자의 파라미터 값으로 쿼리를 직접 실행해보고, 프로파일링으로 병목 지점을 찾아야 합니다. 데이터 스큐(skew) 문제라면 파티셔닝이나 샤딩을 고려해야 합니다.
- • 데이터 양 차이로 실행 계획이 달라질 수 있음
- • 락 대기나 캐시 히트율 차이 확인 필요
- • 실제 문제 파라미터로 직접 테스트 필요
VIP 고객처럼 대량의 주문 이력을 가진 사용자와 일반 사용자 간 쿼리 성능 차이가 발생할 때 진단이 필요합니다.
데이터 분포가 불균등할 때 옵티마이저가 잘못된 실행 계획을 선택하는 것을 방지하기 위한 히스토그램 통계의 역할을 설명해주세요.
Q. MySQL 스키마 변경(ALTER TABLE)을 무중단으로 수행하기 위한 방법들을 설명하고, Online DDL과 pt-online-schema-change 도구의 동작 원리 및 각각의 장단점을 비교해주세요.
테이블 잠금, 복사 방식, 트리거 사용 여부를 고려해보세요.
MySQL 5.6 이상의 Online DDL은 ALGORITHM=INPLACE를 사용하여 테이블 복사 없이 메타데이터만 변경하거나, 최소한의 락으로 스키마 변경을 수행합니다. 인덱스 추가, 컬럼 추가(마지막 위치) 등은 온라인으로 가능하지만, 컬럼 타입 변경이나 중간 위치 컬럼 추가는 테이블 복사가 필요합니다. pt-online-schema-change는 새 테이블을 생성하고 트리거로 변경사항을 동기화하며 데이터를 복사한 후 테이블을 교체하는 방식입니다. Online DDL은 빠르고 간단하지만 대용량 테이블에서는 리소스 사용이 많고, pt-osc는 청크 단위로 처리하여 부하를 분산시킬 수 있지만 트리거 오버헤드가 있습니다. 실무에서는 변경 유형과 테이블 크기에 따라 선택합니다.
- • Online DDL은 INPLACE 방식으로 최소 락 사용
- • pt-osc는 트리거로 동기화하며 청크 단위 복사
- • 변경 유형과 테이블 크기에 따라 방법 선택
서비스 중단 없이 새로운 컬럼을 추가하거나 인덱스를 생성할 때 무중단 스키마 변경 기법이 필요합니다.
Online DDL 수행 중 롤백이 필요한 상황이 발생하면 어떻게 처리해야 하는지 설명해주세요.
Q. 계층 구조 데이터(예: 조직도, 카테고리 트리)를 MySQL에 저장하는 방법으로 인접 리스트(Adjacency List), 경로 열거(Path Enumeration), 중첩 집합(Nested Set) 모델이 있습니다. 각 방식의 쿼리 특성과 장단점을 비교하고, 어떤 상황에서 어느 모델을 선택해야 하는지 설명해주세요.
부모 조회, 서브트리 조회, 삽입/삭제 비용을 고려해보세요.
인접 리스트는 parent_id를 저장하는 가장 간단한 방식으로 부모 조회는 쉽지만 서브트리 조회 시 재귀 쿼리나 애플리케이션 반복이 필요합니다. 경로 열거는 조상 경로를 문자열로 저장하여 LIKE 검색으로 서브트리를 쉽게 조회할 수 있지만, 경로 변경 시 하위 노드를 모두 업데이트해야 합니다. 중첩 집합은 left, right 값으로 범위를 표현하여 서브트리 조회가 매우 빠르지만, 노드 삽입/삭제 시 많은 노드의 값을 업데이트해야 합니다. 읽기가 많고 구조 변경이 적다면 중첩 집합, 구조 변경이 잦다면 인접 리스트가 적합합니다. 실무에서는 인접 리스트와 경로 열거를 혼합하여 사용하는 경우가 많습니다.
- • 인접 리스트는 단순하지만 서브트리 조회가 어려움
- • 경로 열거는 조회는 쉽지만 구조 변경 비용 높음
- • 중첩 집합은 조회 빠르지만 삽입/삭제 비용 높음
조직도, 상품 카테고리, 댓글 대댓글 구조 등 계층적 데이터를 효율적으로 조회하고 관리할 때 사용됩니다.
MySQL 8.0의 재귀 CTE(Common Table Expression)를 사용하여 인접 리스트 모델에서 서브트리를 효율적으로 조회하는 방법을 설명해주세요.
Q. MySQL에서 감사 로그(Audit Log)를 활성화하여 모든 쿼리를 기록하는 것과 슬로우 쿼리 로그, 제너럴 로그의 차이점을 설명하고, 개인정보 보호법 준수를 위해 데이터베이스 접근 이력을 관리할 때 고려해야 할 사항을 설명해주세요.
로그 성능 오버헤드, 민감 정보 노출, 로그 보관 정책을 생각해보세요.
제너럴 로그는 모든 쿼리를 기록하지만 성능 오버헤드가 커서 프로덕션에서는 사용하지 않으며, 슬로우 쿼리 로그는 임계값 이상 쿼리만 기록합니다. 감사 로그는 Enterprise Edition이나 플러그인으로 제공되며 누가 언제 어떤 작업을 했는지 추적할 수 있습니다. 개인정보 접근 이력 관리를 위해서는 사용자 계정별 접근 기록, 조회한 데이터의 범위, IP 주소 등을 함께 기록해야 합니다. 로그에 실제 쿼리가 포함되면 개인정보가 노출될 수 있으므로 마스킹이나 별도 저장소 관리가 필요합니다. 로그 보관 기간을 정책에 맞게 설정하고, 로그 자체에 대한 접근 권한도 엄격히 관리해야 합니다.
- • 제너럴 로그는 모든 쿼리 기록, 감사 로그는 추적 및 컴플라이언스 목적
- • 로그에 개인정보 노출 방지 필요
- • 로그 보관 기간과 접근 권한 관리 중요
금융, 의료 등 규제 산업에서 데이터베이스 접근 이력을 감사하고 컴플라이언스를 준수할 때 사용됩니다.
감사 로그를 외부 SIEM 시스템으로 전송하여 중앙 집중식으로 관리하는 아키텍처의 장점을 설명해주세요.
Q. MySQL에서 대용량 배치 INSERT 작업의 성능을 최적화하는 방법들을 설명하고, INSERT ... VALUES 여러 행 방식, LOAD DATA INFILE, 트랜잭션 배치 처리의 성능 차이와 각각의 장단점을 비교해주세요. 또한 외래 키와 인덱스가 INSERT 성능에 미치는 영향도 함께 설명해주세요.
네트워크 �왕복, 로그 플러시, 인덱스 재구성 비용을 고려해보세요.
단일 INSERT 문으로 여러 행을 삽입하면 네트워크 왕복과 파싱 비용이 줄어 성능이 향상됩니다. LOAD DATA INFILE은 파일에서 직접 읽어 벌크 로드하므로 가장 빠르며, LOCAL 옵션 없이 서버 파일을 사용하면 더 빠릅니다. 트랜잭션을 배치 단위로 묶으면 로그 플러시 횟수가 줄어 성능이 개선되지만, 너무 크면 롤백 비용이 증가합니다. 외래 키 제약조건은 매 INSERT마다 참조 테이블을 확인하므로 성능이 저하되며, 대량 INSERT 시 임시로 비활성화하는 것이 효과적입니다. 인덱스도 매 삽입마다 재구성되므로, 가능하다면 데이터 삽입 후 인덱스를 생성하는 것이 더 빠릅니다. autocommit을 비활성화하고 명시적 트랜잭션을 사용하는 것도 중요합니다.
- • 여러 행 한 번에 삽입으로 네트워크 비용 절감
- • LOAD DATA INFILE이 가장 빠름
- • 외래 키와 인덱스는 임시 비활성화 고려
데이터 마이그레이션, ETL 작업, 대량 로그 적재 등에서 수백만 건의 데이터를 빠르게 삽입할 때 최적화가 필요합니다.
InnoDB의 Change Buffer가 세컨더리 인덱스 INSERT 성능을 어떻게 향상시키는지 설명해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!