Post

02 Explain

02 Explain

1. Note

  • 어떻게 데이터를 빠르고 정확하게 조회할 것인가?
  • 조회 성능을 향상시키기 위해서
    • 인덱스를 거는건 좋은데, 난무해도 문제고
    • 너무 넓은 범위를 조회하게 하면 속도가 느려짐.
    • 단순히 백엔드 개발자의 문제가 아니라
    • 여러가지를 고려하고 판단해야하는 문제!

2. Explain

1. Explain

  • 쿼리가 실제로 어떻게 실행될지 “미리 실행 계획을 보여주는 기능
  • 쿼리를 실행할때 내부적으로 어떻게 조회할지 보여주는 것
    • 어떤 인덱스를 사용할지
    • 테이블을 어떤 순서로 조인할지
    • 풀 스캔 할지, 인덱스 스캔 할지

2. 흐름

1
2
3
4
5
6
7
EXPLAIN SELECT * FROM user WHERE id = 10;

-- 앞에 EXPLAIN 표기하면 
-- 1. type 조회 방식 (ALL = 풀스캔, index, range, ref 등)
-- 2. key	사용된 인덱스
-- 3. rows	예상 조회 row 수
-- 4. Extra	추가 정보 (Using index, Using where 등)

3. 얻을 수 있는 부분

1. 왜 쿼리가 느린지 “정확히” 알 수 있음

  • EXPLAIN을 보면 확인 가능한 것
    • 풀스캔인지 (type = ALL)
    • 인덱스를 타는지 (key)
    • 몇 건을 읽는지 (rows)
  • 이 데이터를 통해서 어떻게 조회해서 이런 조회 속도가 나오는지 등 확인이 가능함.

2. 인덱스가 실제로 먹히는지 검증 가능

  • EXPLAIN의
    • key = null → 인덱스 안 씀
    • type = ALL → 풀스캔
  • 인덱스 만들었는데 효과가 없다면 Explain을 통해서 이유를 알 수 있음

3. JOIN 성능 문제 파악 가능

  • JOIN이 느릴 때 EXPLAIN을 확인 가능한 부분
    • 어떤 테이블부터 읽는지
    • 조인 순서
    • 어떤 인덱스 사용하는지
  • 발견 가능한 문제들
    • N+1 문제
    • 잘못된 조인 순서
    • 불필요한 테이블 스캔

4. “튜닝 전 vs 튜닝 후” 비교 가능

1
2
3
EXPLAIN 실행 → rows = 100만
인덱스 추가
다시 EXPLAIN → rows = 100

3.Explain 결과

1. Mysql(테이블 형태)

idtypekeyrowsExtra
1rangeidx_name100Using where

2. Oracle(실행 순서가 트리 구조로 나옴)

IdOperationNameRowsCost
0SELECT STATEMENT   
1TABLE ACCESS FULLUSERS100010
2INDEX RANGE SCANIDX_NAME1005

3. PostgreSQL

  • 결과값
    1
    2
    
    Seq Scan on categories  (cost=0.00..1.81 rows=4 width=69)
      Filter: (id < 10)
    
  • 테이블 형태로 변형 (별도로 해석 필요함.)

    Node TypeRelationIndexCostRowsWidthFilterExtra
    Seq Scancategories-0.00..1.81469id < 10-

4. Explain의 정보

1. Type(조회 방식)

개념MySQLOraclePostgreSQL
전체 테이블 스캔ALLTABLE ACCESS FULLSeq Scan
인덱스 전체 스캔indexINDEX FULL SCANIndex Scan
인덱스 범위 스캔rangeINDEX RANGE SCANIndex Scan
인덱스 단건 조회refINDEX RANGE / UNIQUE SCANIndex Scan
PK 단건 조회constINDEX UNIQUE SCANIndex Scan
조인 (PK 기준)eq_refINDEX UNIQUE SCANIndex Scan

2. key (사용된 인덱스)

개념MySQLOraclePostgreSQL
사용된 인덱스keyINDEXIndex Scan / Bitmap Index Scan
PK 사용PRIMARYINDEX UNIQUE SCANIndex Scan (PK 포함)
인덱스 없음key = nullTABLE ACCESS FULLSeq Scan

3. rows (예상 조회 row 수)

개념MySQLOraclePostgreSQL
예상 row 수rowsRowsrows
비용없음 (간접)Costcost
row 크기없음Byteswidth

4. Extra (추가 정보)

개념MySQL (Extra)OraclePostgreSQL
WHERE 필터Using whereFILTERFilter
정렬 발생Using filesortSORT ORDER BYSort
임시 테이블Using temporaryTEMP TABLEHash / Materialize
커버링 인덱스Using indexINDEX ONLY SCANIndex Only Scan

5. 조인방식

개념MySQLOraclePostgreSQL
Nested Loop기본NESTED LOOPSNested Loop
Hash Join제한적HASH JOINHash Join
Merge Join없음MERGE JOINMerge Join
This post is licensed under CC BY 4.0 by the author.