Blog
Anki
데이터베이스 문제
20251204 데이터베이스 문제

Q1. 인덱스를 추가했는데 오히려 성능이 떨어졌습니다. 왜 그럴까요?

꼬리 질문
  • 인덱스가 쓰기 성능에 미치는 영향의 구체적인 수치를 알고 있나요?
  • Change Buffer는 무엇이고 어떻게 동작하나요?
  • 어떤 경우에 인덱스를 추가하지 않는 것이 좋을까요?
  • 읽기 성능에서도 인덱스가 오히려 성능을 저하시키는 경우가 있나요?
내 답변 & 평가 결과
  • 내 답변

인덱스를 너무 많이 추가하면 쓰기 성능에 영향을 줄 수 있습니다. InnoDB는 데이터를 쓸 때 Buffer Pool에 먼저 기록하게 되는데 이 Buffer가 차게되면 Index를 생성하는 작업을 합니다. 이 때, Index를 생성하는 작업을 하는동안 락이 걸리게 되는데 인덱스가 너무 많으면 이 작업이 오래 걸리게 되면서 쓰기 성능이 저하되게 됩니다.

  • 평가 결과

총점: 35/100점

Concept - 개념 정의 (8/20점)

  • 정확성: ⚠️ 부분적으로 정확
  • 강점: 인덱스가 쓰기 성능에 영향을 준다는 핵심 개념은 언급함
  • 약점: Buffer Pool과 인덱스 생성 과정에 대한 설명이 부정확함. Buffer Pool이 차면 인덱스를 생성한다는 설명은 틀림
  • 개선 방향: 인덱스 추가 시 INSERT/UPDATE/DELETE 시 인덱스도 함께 갱신해야 한다는 본질적 원인을 설명해야 함

Logic - 원리/동작 방식 (7/20점)

  • 정확성: ❌ 동작 원리 설명이 부정확
  • 강점: 락으로 인한 성능 저하 가능성을 언급
  • 약점: Buffer Pool은 인덱스 생성이 아닌 데이터 캐싱 용도임. InnoDB의 Change Buffer 개념과 혼동한 것으로 보임
  • 개선 방향: B-Tree 구조 유지를 위한 페이지 분할, 인덱스별 Random I/O 발생 등 실제 원리를 설명해야 함

Example - 예시/비유 (5/20점)

  • 강점: 없음
  • 약점: 구체적인 예시, 수치, 코드가 전혀 없음
  • 개선 방향: 인덱스 개수별 INSERT 성능 변화 그래프, 실제 시나리오 예시 추가 필요

Application - 활용/적용 (8/20점)

  • 강점: 인덱스를 과도하게 추가하면 안 된다는 실무 관점 언급
  • 약점: 구체적으로 어떤 상황에서 인덱스를 추가/제거해야 하는지 가이드 없음
  • 개선 방향: 읽기 vs 쓰기 비율에 따른 인덱스 전략, 모니터링 방법 등 추가

Relation - 관련 개념/심화 (7/20점)

  • 강점: Buffer Pool 개념 언급 시도
  • 약점: Change Buffer, Covering Index, 클러스터드 인덱스 등 관련 개념 언급 없음
  • 개선 방향: 관련 개념들과의 연결, 트레이드오프 분석 추가
모범 답변 보기

💬 면접 답변 (2-3분 분량)

인덱스를 추가했는데 오히려 성능이 떨어지는 경우는 크게 두 가지 상황이 있습니다.

첫째, 쓰기 성능 저하입니다. 테이블에 인덱스가 추가되면 INSERT, UPDATE, DELETE 시마다 해당 인덱스도 함께 갱신해야 합니다. 인덱스는 B-Tree 구조로 정렬된 상태를 유지해야 하므로, 새로운 데이터가 삽입될 때 올바른 위치를 찾아 삽입하고, 필요시 페이지 분할(Page Split)이 발생합니다. 인덱스가 5개라면 INSERT 한 번에 최대 5번의 인덱스 갱신이 필요해 쓰기 성능이 급격히 저하됩니다. Use The Index Luke에 따르면 인덱스가 없을 때 대비 1개만 추가해도 INSERT 성능이 약 100배 느려질 수 있습니다.

둘째, 읽기 성능도 저하될 수 있습니다. 옵티마이저가 잘못된 인덱스를 선택하거나, 카디널리티가 낮은 컬럼의 인덱스를 사용하면 오히려 성능이 떨어집니다. 예를 들어 성별처럼 2개의 값만 있는 컬럼에 인덱스를 걸면, 인덱스를 통해 50%의 데이터를 읽어야 하는데, 이때 Random I/O가 발생하여 Sequential I/O를 사용하는 Full Table Scan보다 느려질 수 있습니다. MySQL 옵티마이저는 일반적으로 전체 데이터의 20-30% 이상을 읽어야 할 때 Full Table Scan을 선택합니다.

따라서 인덱스는 무조건 많다고 좋은 것이 아니라, 읽기와 쓰기 비율, 쿼리 패턴을 고려해 신중하게 추가해야 합니다.


📋 상세 분석 (암기/복습용)

  • 핵심 포인트 💡:
    • 인덱스 추가 시 모든 DML(INSERT/UPDATE/DELETE)에서 인덱스 갱신 오버헤드 발생
    • 인덱스 1개 추가만으로 INSERT 성능 약 100배 저하 가능
    • 카디널리티가 낮은 인덱스는 읽기 성능도 저하시킬 수 있음

Concept - 개념 정의

인덱스 추가로 인한 성능 저하는 쓰기 오버헤드 증가옵티마이저의 비효율적 인덱스 선택 두 가지 원인에서 발생합니다.

Logic - 원리/동작 방식

  • 쓰기 성능 저하 원리:

    • INSERT 시 데이터 저장 + 각 인덱스의 B-Tree에 엔트리 추가
    • B-Tree 정렬 상태 유지를 위한 페이지 분할(Page Split) 발생
    • 인덱스별 Random I/O 발생으로 디스크 접근 증가
  • 읽기 성능 저하 원리:

    • 카디널리티가 낮은 인덱스 사용 시 대량의 데이터 스캔 필요
    • 인덱스 → 테이블 데이터 접근 시 Random I/O 발생
    • 데이터가 분산되어 있으면 Sequential I/O(Full Scan)보다 비효율적

출처: Use The Index Luke - Insert (opens in a new tab)

"The number of indexes on a table is the most dominant factor for insert performance. The more indexes a table has, the slower the execution becomes."

Example - 예시/비유

  • 일상 비유: 도서관에 책을 추가할 때, 책장에 꽂기만 하면 빠르지만(힙 테이블), 제목순/저자순/출판일순 등 여러 목록(인덱스)을 모두 업데이트해야 한다면 시간이 훨씬 오래 걸립니다.

  • 성능 변화 그래프:

    인덱스 개수 | INSERT 시간 (상대값)
    -----------|--------------------
    0개        | 0.0003초
    1개        | 0.03초 (약 100배 증가)
    2개        | 0.04초
    3개        | 0.05초
    5개        | 0.08초
  • 코드 예시:

    -- 낮은 카디널리티 인덱스의 문제
    CREATE INDEX idx_gender ON users(gender);  -- 값이 'M', 'F' 두 개뿐
     
    -- 이 쿼리는 Full Table Scan이 더 빠름
    SELECT * FROM users WHERE gender = 'M';  -- 50% 데이터 조회
     
    -- EXPLAIN으로 확인
    EXPLAIN SELECT * FROM users WHERE gender = 'M';
    -- type: ALL (옵티마이저가 인덱스 사용 안 함)

Application - 활용/적용

  • 인덱스를 신중히 추가해야 하는 경우:

    • 쓰기 비율이 높은 테이블 (로그, 이벤트 테이블)
    • 대량 INSERT가 빈번한 배치 작업
    • 이미 3-5개 이상의 인덱스가 있는 테이블
  • 인덱스 추가가 효과적인 경우:

    • 읽기 비율이 압도적으로 높은 테이블
    • WHERE, JOIN, ORDER BY에 자주 사용되는 고카디널리티 컬럼
    • Covering Index로 테이블 접근을 완전히 회피할 수 있는 경우
  • 모니터링 방법:

    -- 인덱스 사용 현황 확인
    SELECT * FROM sys.schema_unused_indexes;
     
    -- 중복 인덱스 확인
    SELECT * FROM sys.schema_redundant_indexes;

Relation - 관련 개념/심화

  • 관련 개념:

    • Change Buffer: InnoDB가 세컨더리 인덱스 변경을 버퍼링하여 Random I/O를 줄이는 최적화 기법
    • Covering Index: 인덱스만으로 쿼리를 처리해 테이블 접근을 없앰
    • 클러스터드 인덱스: PK 기준으로 데이터 자체가 정렬되어 저장됨
  • 비교:

    구분Full Table ScanIndex Scan
    I/O 패턴Sequential I/ORandom I/O
    효율적인 경우대량 데이터 조회소량 데이터 조회
    데이터 비율20-30% 이상20% 미만
  • 트레이드오프:

    • 장점: 읽기 쿼리 성능 향상, ORDER BY 최적화
    • 단점: 쓰기 성능 저하, 저장 공간 증가, 옵티마이저 혼란 가능성

Q2. EXPLAIN 결과에서 type이 ALL로 나오는데 어떻게 개선할 수 있나요?

꼬리 질문
  • EXPLAIN의 type 컬럼에서 각 값의 성능 순서를 알고 있나요?
  • type이 ALL이어도 괜찮은 경우가 있나요?
  • 복합 인덱스를 설계할 때 컬럼 순서는 어떻게 결정하나요?
  • EXPLAIN 결과의 rows 값이 실제 데이터와 다른 이유는 무엇인가요?
내 답변 & 평가 결과
  • 내 답변

type이 all이라는 것은 Full Table Scan을 의미합니다. 카디널리티가 낮은 컬럼을 Index로 걸게 되면 Scan 결과 20% 이상의 데이터가 존재한다고 옵티마이저가 판단하면 Sequential IO를 하는 Full Text Scan을 수행하게 됩니다. 이를 개선하기 위해선 카디널리티가 높은 Index와 복합 인덱스를 거는 방식을 취할 수 있습니다.

  • 평가 결과

총점: 55/100점

Concept - 개념 정의 (14/20점)

  • 정확성: ✅ 정확
  • 강점: type=ALL이 Full Table Scan임을 정확히 설명
  • 약점: "Full Text Scan"이라고 표기했는데 "Full Table Scan"이 정확한 용어
  • 개선 방향: ALL 외의 다른 type 값들과 비교 설명 추가

Logic - 원리/동작 방식 (12/20점)

  • 정확성: ✅ 부분적으로 정확
  • 강점: 카디널리티와 옵티마이저 판단 기준(20%) 언급
  • 약점: 왜 Sequential I/O가 Random I/O보다 대량 데이터에서 효율적인지 원리 설명 부족
  • 개선 방향: 디스크 I/O 패턴에 따른 성능 차이 원리 추가

Example - 예시/비유 (8/20점)

  • 강점: 카디널리티 개념 언급
  • 약점: 구체적인 EXPLAIN 결과 예시, 개선 전후 비교가 없음
  • 개선 방향: 실제 EXPLAIN 출력 결과와 개선 예시 추가

Application - 활용/적용 (12/20점)

  • 강점: 카디널리티 높은 인덱스, 복합 인덱스라는 해결책 제시
  • 약점: 복합 인덱스의 컬럼 순서, 구체적인 적용 방법 설명 부족
  • 개선 방향: 복합 인덱스 설계 원칙, 인덱스 힌트 등 추가

Relation - 관련 개념/심화 (9/20점)

  • 강점: 카디널리티, Sequential I/O 개념 연결 시도
  • 약점: EXPLAIN의 다른 컬럼들, Covering Index, Index Hint 등 연결 부족
  • 개선 방향: type 외의 key, rows, Extra 컬럼 해석 방법 추가
모범 답변 보기

💬 면접 답변 (2-3분 분량)

EXPLAIN에서 type이 ALL은 Full Table Scan을 의미하며, 테이블의 모든 행을 순차적으로 읽는 가장 비효율적인 접근 방식입니다. 다만 ALL이 항상 나쁜 것은 아닙니다. 테이블 크기가 작거나, 실제로 대부분의 데이터를 읽어야 하는 경우에는 ALL이 최적일 수 있습니다.

type의 성능 순서는 system > const > eq_ref > ref > range > index > ALL 순서이며, 가능하면 range 이상을 목표로 해야 합니다.

ALL을 개선하는 방법은 여러 가지가 있습니다.

첫째, WHERE 절에 사용되는 컬럼에 인덱스를 추가합니다. 이때 카디널리티가 높은 컬럼을 선택해야 합니다. 카디널리티가 낮으면 옵티마이저가 인덱스를 사용해도 전체의 20-30% 이상을 읽어야 한다고 판단하면 오히려 Full Table Scan을 선택합니다.

둘째, 복합 인덱스를 활용합니다. 여러 컬럼을 조합해 선택성을 높일 수 있습니다. 복합 인덱스 설계 시에는 WHERE 절의 등호 조건 컬럼을 앞에, 범위 조건을 뒤에 배치하고, 카디널리티가 높은 컬럼을 우선 배치하는 것이 좋습니다.

셋째, 쿼리 자체를 검토합니다. SELECT *을 피하고 필요한 컬럼만 조회하면 Covering Index 활용이 가능해집니다. 또한 LIKE '%keyword%' 같은 패턴은 인덱스를 사용할 수 없으므로 LIKE 'keyword%'로 변경하거나 Full-Text Index를 고려해야 합니다.


📋 상세 분석 (암기/복습용)

  • 핵심 포인트 💡:
    • type=ALL은 Full Table Scan이며 가장 비효율적인 접근 방식
    • 성능 순서: system > const > eq_ref > ref > range > index > ALL
    • 카디널리티가 높은 컬럼에 인덱스 추가, 복합 인덱스 활용으로 개선

Concept - 개념 정의

EXPLAIN의 type 컬럼은 MySQL이 테이블에 접근하는 방식을 나타내며, ALL은 테이블의 모든 행을 처음부터 끝까지 스캔하는 Full Table Scan을 의미합니다.

Logic - 원리/동작 방식

  • type별 동작 방식:

    • const/system: PK나 Unique 인덱스로 1건만 조회 (상수 시간)

    • eq_ref: JOIN에서 PK/Unique로 1건씩 매칭

    • ref: 인덱스로 여러 행 조회 (등호 조건)

    • range: 인덱스로 범위 검색 (BETWEEN, <, >)

    • index: 인덱스 전체 스캔 (데이터 파일 접근 X)

      • type='index'는 인덱스를 처음부터 끝까지 순차적으로 스캔하지만, 데이터 파일에는 접근하지 않는 경우입니다
      • 주요 발생 케이스 MySQL 공식 문서 - EXPLAIN Output (opens in a new tab):
        1. Covering Index: 쿼리에 필요한 모든 컬럼이 인덱스에 포함되어 있어 데이터 파일 접근이 불필요한 경우 (Extra: Using index로 표시됨)

        2. Leading Wildcard 검색: LIKE '%keyword' 같은 패턴으로 전체 스캔이 필요하지만, 인덱스에 필요한 컬럼이 모두 포함된 경우

        3. 비효율적인 인덱스 순서: 인덱스가 모든 컬럼을 커버하지만 순서가 최적이 아닌 경우

      MySQL EXPLAIN 분석 가이드 (opens in a new tab)에서 "The index join type is the same as ALL, except that the index tree is scanned. This occurs two ways: If the index is a covering index for the queries and can be used to satisfy all data required from the table, only the index tree is scanned" 라고 명시되어 있습니다.

      • 성능 영향: type='index'는 ALL(Full Table Scan) 다음으로 두 번째로 비효율적인 실행 계획입니다. Covering Index를 통한 최적화가 가능한 경우가 아니라면 인덱스 설계를 재검토해야 합니다
    • ALL: 테이블 전체 스캔 (가장 느림)

  • Full Table Scan이 선택되는 조건:

    • 조건 컬럼에 인덱스가 없음
    • 인덱스가 있지만 카디널리티가 낮아 효율성이 떨어짐
    • 함수나 연산으로 인덱스 컬럼이 가공됨

출처: SitePoint - Using EXPLAIN (opens in a new tab)

"all – the entire table is scanned to find matching rows for the join. This is the worst join type and usually indicates the lack of appropriate indexes on the table."

Example - 예시/비유

  • 일상 비유: 도서관에서 책을 찾을 때, 색인(인덱스) 없이 모든 책장을 처음부터 끝까지 확인하는 것이 ALL입니다.

  • EXPLAIN 결과 예시:

    -- 개선 전: type=ALL
    EXPLAIN SELECT * FROM orders WHERE customer_id = 1234;
    -- id: 1, type: ALL, rows: 326, Extra: Using where
     
    -- 인덱스 추가
    CREATE INDEX idx_customer_id ON orders(customer_id);
     
    -- 개선 후: type=ref
    EXPLAIN SELECT * FROM orders WHERE customer_id = 1234;
    -- id: 1, type: ref, key: idx_customer_id, rows: 4
  • 복합 인덱스 설계 예시:

    -- 쿼리: WHERE status = 'active' AND created_at > '2024-01-01'
     
    -- 좋은 순서: 등호 조건 → 범위 조건
    CREATE INDEX idx_status_created ON orders(status, created_at);
     
    -- 나쁜 순서: 범위 조건이 앞에 오면 created_at 이후 컬럼은 인덱스 활용 불가
    CREATE INDEX idx_created_status ON orders(created_at, status);

Application - 활용/적용

  • ALL을 개선하는 체크리스트:

    • WHERE/JOIN 컬럼에 인덱스 확인
    • possible_keys가 NULL이면 인덱스 추가
    • key가 NULL이면 인덱스가 있어도 미사용 → 쿼리 검토
    • rows 수가 크면 인덱스 효율 재검토
  • 쿼리 최적화 팁:

    -- ❌ 인덱스 사용 불가 (컬럼 가공)
    SELECT * FROM users WHERE YEAR(created_at) = 2024;
     
    -- ✅ 인덱스 사용 가능 (범위 조건)
    SELECT * FROM users WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';
     
    -- ❌ 인덱스 사용 불가 (앞 와일드카드)
    SELECT * FROM users WHERE name LIKE '%kim%';
     
    -- ✅ 인덱스 사용 가능 (뒤 와일드카드만)
    SELECT * FROM users WHERE name LIKE 'kim%';

Relation - 관련 개념/심화

  • 관련 개념:

    • Covering Index: 인덱스만으로 쿼리 처리 (Extra: Using index)
    • Index Hint: FORCE INDEX, USE INDEX로 옵티마이저 유도
    • rows 컬럼: 예상 스캔 행 수 (통계 기반, 정확하지 않을 수 있음)
  • EXPLAIN 주요 컬럼 해석:

    컬럼의미최적화 포인트
    type접근 방식range 이상 목표
    key사용된 인덱스NULL이면 인덱스 미사용
    rows예상 스캔 행수작을수록 좋음
    Extra추가 정보Using filesort, Using temporary 주의
  • 트레이드오프:

    • 장점: 인덱스 추가로 읽기 성능 대폭 향상
    • 단점: 쓰기 성능 저하, 저장 공간 증가, 인덱스 유지보수 비용

Q3. 쿼리 속도가 느린데 인덱스 문제인지 어떻게 판단하나요?

꼬리 질문
  • EXPLAIN 외에 쿼리 성능을 분석하는 다른 도구는 무엇이 있나요?
  • Slow Query Log는 어떻게 활용하나요?
  • 인덱스 문제가 아닌 다른 성능 저하 원인은 무엇이 있나요?
  • 프로파일링 결과에서 어떤 지표를 중점적으로 봐야 하나요?
내 답변 & 평가 결과
  • 내 답변

explain 찍어보면 되지 않을까요?

  • 평가 결과

총점: 15/100점

Concept - 개념 정의 (5/20점)

  • 정확성: ⚠️ 불완전
  • 강점: EXPLAIN이 핵심 도구임을 인지
  • 약점: 단답형 대답으로 개념 정의가 없음
  • 개선 방향: EXPLAIN이 무엇을 보여주고 어떻게 인덱스 문제를 판단하는지 설명 필요

Logic - 원리/동작 방식 (2/20점)

  • 정확성: ❌ 설명 없음
  • 강점: 없음
  • 약점: EXPLAIN 결과에서 어떤 항목을 어떻게 해석해야 하는지 설명 없음
  • 개선 방향: type, key, rows, Extra 등 핵심 컬럼 해석 방법 추가

Example - 예시/비유 (2/20점)

  • 강점: 없음
  • 약점: 구체적인 예시, 결과 해석 과정이 전혀 없음
  • 개선 방향: 실제 EXPLAIN 결과 예시와 분석 과정 추가

Application - 활용/적용 (3/20점)

  • 강점: EXPLAIN 도구 언급
  • 약점: 실무에서 어떻게 적용하는지 설명 없음
  • 개선 방향: Slow Query Log, EXPLAIN ANALYZE, 프로파일링 등 실무 활용법 추가

Relation - 관련 개념/심화 (3/20점)

  • 강점: 없음
  • 약점: 인덱스 외의 다른 성능 저하 원인, 추가 분석 도구 언급 없음
  • 개선 방향: 락 경합, 하드웨어 이슈, N+1 쿼리 등 다른 원인도 언급
모범 답변 보기

💬 면접 답변 (2-3분 분량)

쿼리 속도가 느릴 때 인덱스 문제인지 판단하는 방법은 단계적으로 접근합니다.

첫째, EXPLAIN으로 실행 계획을 확인합니다. 핵심적으로 봐야 할 컬럼은 type, key, rows, Extra입니다. type이 ALL이거나 key가 NULL이면 인덱스를 사용하지 않는 것이고, rows 값이 크면 많은 행을 스캔하고 있다는 의미입니다. Extra에 Using filesort나 Using temporary가 있으면 정렬이나 임시 테이블 생성으로 인한 오버헤드가 발생하고 있습니다.

둘째, EXPLAIN ANALYZE를 사용하면 예상 실행 계획이 아닌 실제 실행 결과를 확인할 수 있습니다. 예상 rows와 실제 rows의 차이가 크면 통계가 오래된 것이므로 ANALYZE TABLE로 통계를 갱신해야 합니다.

셋째, Slow Query Log를 활성화하면 설정한 임계값 이상의 느린 쿼리를 자동으로 기록해줍니다. 이를 통해 문제가 되는 쿼리를 식별할 수 있습니다.

다만 쿼리 속도 저하가 항상 인덱스 문제는 아닙니다. 락 경합, 네트워크 지연, 메모리 부족으로 인한 디스크 I/O, N+1 쿼리 패턴 등 다른 원인도 있으므로 SHOW PROCESSLIST, SHOW ENGINE INNODB STATUS 등으로 종합적으로 분석해야 합니다.


📋 상세 분석 (암기/복습용)

  • 핵심 포인트 💡:
    • EXPLAIN의 type, key, rows, Extra 컬럼으로 인덱스 사용 여부 확인
    • EXPLAIN ANALYZE로 실제 실행 결과 vs 예상치 비교
    • Slow Query Log, SHOW PROCESSLIST 등 추가 도구 활용

Concept - 개념 정의

쿼리 성능 분석은 EXPLAIN을 통해 옵티마이저의 실행 계획을 확인하고, 인덱스 사용 여부와 예상 비용을 판단하는 과정입니다. 인덱스 문제 외에도 다양한 원인이 있을 수 있으므로 종합적 분석이 필요합니다.

Logic - 원리/동작 방식

  • EXPLAIN 핵심 컬럼 해석:

    • type: 접근 방식 (ALL이면 Full Scan)
    • possible_keys: 사용 가능한 인덱스 목록
    • key: 실제 사용된 인덱스 (NULL이면 미사용)
    • rows: 예상 스캔 행 수 (클수록 비효율)
    • Extra: 추가 정보 (Using index = 좋음, Using filesort = 주의)
  • 인덱스 문제 판단 기준:

    • type이 ALL 또는 index
    • key가 NULL (인덱스 미사용)
    • rows가 테이블 전체 행 수에 가까움
    • Extra에 Using where만 있고 Using index 없음

출처: MySQL 공식 문서 - EXPLAIN Output (opens in a new tab)

Example - 예시/비유

  • 일상 비유: 의사가 환자를 진단할 때 X-ray(EXPLAIN), MRI(EXPLAIN ANALYZE), 혈액검사(Slow Query Log) 등 여러 검사를 종합해 원인을 파악하는 것과 같습니다.

  • 분석 과정 예시:

    -- 1. 기본 EXPLAIN
    EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'pending';
    -- type: ALL, key: NULL, rows: 50000 → 인덱스 문제!
     
    -- 2. 인덱스 추가 후 재확인
    CREATE INDEX idx_user_status ON orders(user_id, status);
    EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'pending';
    -- type: ref, key: idx_user_status, rows: 15 → 개선됨!
     
    -- 3. EXPLAIN ANALYZE로 실제 성능 확인 (MySQL 8.0.18+)
    EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 100 AND status = 'pending';
    -- actual time=0.05..0.08, rows=15, loops=1
  • Slow Query Log 설정:

    -- 2초 이상 걸리는 쿼리 로깅
    SET GLOBAL slow_query_log = 'ON';
    SET GLOBAL long_query_time = 2;
    SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

Application - 활용/적용

  • 인덱스 문제 진단 체크리스트:

    1. EXPLAIN으로 type, key 확인
    2. key가 NULL → 인덱스 추가 검토
    3. type이 ALL → 카디널리티, 쿼리 조건 검토
    4. rows가 크면 → 복합 인덱스, 조건 추가 검토
  • 인덱스 외 성능 저하 원인:

    • 락 경합: SHOW PROCESSLIST, SHOW ENGINE INNODB STATUS

    • N+1 쿼리: 애플리케이션 레벨에서 쿼리 로그 확인

    • 버퍼 풀 부족: SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool%'

    • 디스크 I/O: iostat, iotop 등 OS 도구

      • iostat 주요 지표 Sematext - Linux Disk IO Monitoring Guide (opens in a new tab):
        • %util (디스크 사용률)디스크가 바쁜 시간의 비율. 80-90% 이상이면 디스크가 병목 지점일 가능성이 높음

        • await (평균 대기 시간)I/O 요청이 서비스되기까지 대기한 평균 시간(ms). %util보다 신뢰할 수 있는 지표

          • 정상 범위: 20-40ms는 괜찮은 수준
          • 임계값: 95% 응답 시간이 단일 동시성 대비 3배 이상 증가하면 과부하 상태로 판단
        • r_await / w_await: 읽기/쓰기를 분리한 대기 시간. await보다 더 유용한 지표

        • avgqu-sz (평균 큐 크기)디바이스에서 대기 중인 평균 요청 수. 지속적으로 높으면 디스크가 요청을 처리하는데 어려움을 겪고 있음

        • r/s, w/s: 초당 읽기/쓰기 작업 수

      Webdock - Debug Disk Performance (opens in a new tab)에서 "await: Average IO wait time in ms - High values indicate slow disk response times. %util: Disk utilization - Percentage of time the disk is busy. If this is consistently above 80-90%, the disk may be a bottleneck" 라고 명시되어 있습니다.

      • iotop 주요 기능: 프로세스별 실시간 I/O 사용량 모니터링. 어떤 프로그램이 디스크를 실제로 사용하고 있는지 확인
      • %iowait (CPU I/O 대기 시간): CPU가 I/O 작업 완료를 기다리며 유휴 상태로 있는 시간의 비율
        • 20% 이상이면 시스템이 I/O 병목 상태임을 나타냄

Relation - 관련 개념/심화

  • 관련 도구:

    • pt-query-digest: Slow Query Log 분석 도구
    • MySQL Enterprise Monitor: 상용 모니터링
    • Performance Schema: 상세 성능 메트릭 수집
  • 성능 분석 도구 비교:

    도구용도특징
    EXPLAIN실행 계획 분석예상치 기반, 빠름
    EXPLAIN ANALYZE실제 실행 분석실제 수행, 정확함
    Slow Query Log느린 쿼리 기록사후 분석용
    SHOW PROCESSLIST현재 실행 중인 쿼리실시간 모니터링
  • 트레이드오프:

    • EXPLAIN: 빠르지만 예상치라 실제와 다를 수 있음
    • EXPLAIN ANALYZE: 정확하지만 실제로 쿼리를 실행함