JSCODE Logo
JSCODE 박재성JSCODE 제이온JSCODE 시니
과외유튜브블로그후기
완강 후기 이벤트블로그 리뷰 이벤트AWS SAA 합격 후기 이벤트
회사명 : JSCODE대표 : 박재성사업자 등록번호 : 244-22-01557통신판매업 : 제 2023-인천미추홀-0381 호

서울특별시 구로구 경인로 20가길 11(오류동, 아델리아)

Copyright ⓒ 2026 JSCODE - 최상위 현업 개발자들의 프로그래밍 교육 All rights reserved.

이용약관개인정보처리방침

비전공자도 이해할 수 있는 MySQL 성능 최적화 입문/실전 (SQL 튜닝편)

MySQL 성능 최적화를 본격적으로 배우기 전에!

신입 백엔드 면접에서 자주 물어보는 ‘DB 성능 최적화’ 경험?!
DB 성능 개선할 때 ‘SQL 튜닝’을 가장 먼저 해야 하는 이유 (vs 스케일업, 레플리케이션, 샤딩, 캐싱)
성능 개선을 위한 MySQL 구조 파악 / SQL 튜닝의 핵심

인덱스(Index) 기본 개념 / 실전 활용법

인덱스(Index)란?
[실습] 인덱스 직접 설정해보기 / 성능 측정해보기
기본으로 설정되는 인덱스 (PK)
제약 조건을 추가하면 자동으로 생성되는 인덱스 (UNIQUE)
[실습] 인덱스를 무식하게 많이 걸면 어떻게 될까?
멀티 컬럼 인덱스 (Mulitple-Column Index)란?
[실습] 멀티 컬럼 인덱스 직접 설정해보기 / 작동방식 이해하기
멀티 컬럼 인덱스 생성 시 주의점
커버링 인덱스(Covering Index)란?

실행 계획(EXPLAIN)을 활용해 성능 저하 요인 찾아내기

SQL문의 ‘실행 계획’ 사용해보기 (EXPLAIN)
실행 계획에서 type 의미 분석하기 (ALL, index)
실행 계획에서 type 의미 분석하기 (const, range, ref)

SQL문 튜닝 연습하기

[실습] 한 번에 너무 많은 데이터를 조회하는 SQL문 튜닝하기
[실습] WHERE문이 사용된 SQL문 튜닝하기 - 1
[실습] WHERE문이 사용된 SQL문 튜닝하기 - 2
[실습] 인덱스를 걸었는데도 인덱스가 작동하지 않는 경우 - 1
[실습] 인덱스를 걸었는데도 인덱스가 작동하지 않는 경우 - 2
[실습] ORDER BY문이 사용된 SQL문 튜닝하기
[실습] WHERE문에 인덱스를 걸기 vs ORDER BY문에 인덱스를 걸기
[실습] HAVING문이 사용된 SQL문 튜닝하기

실전 SQL문으로 튜닝 직접 해보기

[실습] 유저 이름으로 특정 기간에 작성된 글 검색하는 SQL문 튜닝하기
[실습] 특정 부서에서 최대 연봉을 가진 사용자들 조회하는 SQL문 튜닝하기
[실습] 부서별 최대 연봉을 가진 사용자들 조회하는 SQL문 튜닝하기
[실습] 2023년 주문 데이터 조회하는 SQL문 튜닝하기
[실습] 2024년 1학기 평균 성적이 100점인 학생 조회하는 SQL문 튜닝하기
[실습] 좋아요 많은 순으로 게시글 조회하는 SQL문 튜닝하기
← 블로그 목록으로 돌아가기

SQL문의 ‘실행 계획’ 사용해보기 (EXPLAIN)

JSCODE 박재성
JSCODE 박재성
2026. 03. 24.
author
JSCODE 박재성
category
MySQL
createdAt
Dec 2, 2025 10:02 AM
isPublic
isPublic
series
비전공자도 이해할 수 있는 MySQL 성능 최적화 입문/실전 (SQL 튜닝편)
slug
explain-execution-plan
type
post
updatedAt
Mar 24, 2026 09:00

✅ ’실행 계획’이란 ?

옵티마이저가 SQL문을 어떤 방식으로 어떻게 처리할 지를 계획한 걸 의미한다. 이 실행 계획을 보고 비효율적으로 처리하는 방식이 있는 지 점검하고, 비효율적인 부분이 있다면 더 효율적인 방법으로 SQL문을 실행하게끔 튜닝을 하는 게 목표다.
notion image
 
 

✅ 실행 계획을 확인하는 방법

# 실행 계획 조회하기 EXPLAIN [SQL문] # 실행 계획에 대한 자세한 정보 조회하기 EXPLAIN ANALYZE [SQL문]
 
 

✅ 실행 계획 사용해보기

  1. 테이블 생성
    1. DROP TABLE IF EXISTS users; # 기존 테이블 삭제 CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), age INT );
 
  1. 데이터 삽입
    1. INSERT INTO users (name, age) VALUES ('박미나', 26), ('김미현', 23), ('김민재', 21), ('이재현', 24), ('조민규', 23), ('하재원', 22), ('최지우', 22);
 
  1. 실행 계획 조회하기
    1. 👨🏻‍🏫
      한 번에 모든 값을 다 해석하고 싶은 욕심 때문에 이해하는 데 오래 걸린다. 정말 필수적이고 자주 보는 값들 위주만 짚고 기억하고 넘어가자. 필수적이고 핵심적인 값들이 익숙해지고 나서 나머지 옵션들을 찾아서 공부하면 된다.
       
      i) 실행 계획 조회하기
      EXPLAIN SELECT * FROM users WHERE age = 23;
      notion image
      • id : 실행 순서
      • select_type : (처음에는 몰라도 됨)
      • table : 조회한 테이블 명
      • partitions : (처음에는 몰라도 됨)
      • type : 테이블의 데이터를 어떤 방식으로 조회하는 지 ⭐️⭐️⭐️
      • possible keys : 사용할 수 있는 인덱스 목록을 출력 ⭐️
      • key : 데이터 조회할 때 실제로 사용한 인덱스 값 ⭐️
      • key_len : (처음에는 몰라도 됨)
      • ref : 테이블 조인 상황에서 어떤 값을 기준으로 데이터를 조회했는 지
      • rows : SQL문 수행을 위해 접근하는 데이터의 모든 행의 수 (= 데이터 액세스 수) ⭐️⭐️⭐️
        • → 이 값을 줄이는 게 SQL 튜닝의 핵심이다!
      • filtered : 필터 조건에 따라 어느 정도의 비율로 데이터를 제거했는 지 의미
        • → filtered의 값이 30이라면 100개의 데이터를 불러온 뒤 30개의 데이터만 실제로 응답하는데 사용했음을 의미한다.
          → filtered 비율이 낮을 수록 쓸데없는 데이터를 많이 불러온 것.
      • Extra : 부가적인 정보를 제공 ⭐️
        • → ex. Using where, Using index
       
      주의점) rows, filtered의 값은 정확한 수치가 아닌 추정값이기 때문에 오차가 있을 수 있다.
ii) 실행 계획에 대한 자세한 정보 조회하기
EXPLAIN ANALYZE SELECT * FROM users WHERE age = 23;
notion image
  • Table scan on users : users 테이블을 풀 스캔했다.
    • rows : 접근한 데이터의 행의 수
    • actual time=0.0437..0.0502
      • 0.0437 (앞에 있는 숫자) : 첫 번째 데이터에 접근하기까지의 시간
      • 0.0502 (뒤에 있는 숫자) : 마지막 데이터까지 접근한 시간
  • Filter: (users.age = 23) : 필터링을 통해 데이터를 추출했다. 필터링을 할 때의 조건은 users.age = 23이다.
 
위 작업을 한 번에 이어서 해석해보면 다음과 같다.
users 테이블의 모든 데이터(7개)에 접근했다. 그러고 그 데이터 중 age = 23의 조건을 만족하는 데이터만 필터링해서 조회해왔다.
 
 
 
 
📎
이 글은 비전공자도 이해할 수 있는 MySQL 성능 최적화 입문/실전 (SQL 튜닝편) 강의의 수업 자료 중 일부입니다.