JSCODE Logo
면접 스터디블로그후기멘토진
회사명 : JSCODE대표 : 박재성사업자 등록번호 : 244-22-01557통신판매업 : 제 2023-인천미추홀-0381 호
학원 명칭 : 제이에스코드(JSCODE)원격학원학원설립ㆍ운영 등록번호 : 제6063호

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

Copyright ⓒ 2025 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문 튜닝하기
← 블로그 목록으로 돌아가기

[실습] 2024년 1학기 평균 성적이 100점인 학생 조회하는 SQL문 튜닝하기

JSCODE 박재성
JSCODE 박재성
2025-12-02
author
JSCODE 박재성
category
MySQL
createdAt
Dec 2, 2025
series
비전공자도 이해할 수 있는 MySQL 성능 최적화 입문/실전 (SQL 튜닝편)
slug
2024-average-score-100-sql-tuning
type
post
updatedAt
Dec 2, 2025 10:54 AM

✅ 2024년 1학기 평균 성적이 100점인 학생 조회하기

  1. 기본 테이블 셋팅
    1. DROP TABLE IF EXISTS scores; DROP TABLE IF EXISTS subjects; DROP TABLE IF EXISTS students; CREATE TABLE students ( student_id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), age INT ); CREATE TABLE subjects ( subject_id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) ); CREATE TABLE scores ( score_id INT AUTO_INCREMENT PRIMARY KEY, student_id INT, subject_id INT, year INT, semester INT, score INT, FOREIGN KEY (student_id) REFERENCES students(student_id), FOREIGN KEY (subject_id) REFERENCES subjects(subject_id) );
 
  1. 더미 데이터 추가
    1. -- 높은 재귀(반복) 횟수를 허용하도록 설정 -- (아래에서 생성할 더미 데이터의 개수와 맞춰서 작성하면 된다.) SET SESSION cte_max_recursion_depth = 1000000; -- students 테이블에 더미 데이터 삽입 INSERT INTO students (name, age) WITH RECURSIVE cte (n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM cte WHERE n < 1000000 -- 생성하고 싶은 더미 데이터의 개수 ) SELECT CONCAT('Student', LPAD(n, 7, '0')) AS name, -- 'User' 다음에 7자리 숫자로 구성된 이름 생성 FLOOR(1 + RAND() * 100) AS age -- 1부터 100 사이의 랜덤한 점수 생성 FROM cte; -- subjects 테이블에 과목 데이터 삽입 INSERT INTO subjects (name) VALUES ('Mathematics'), ('English'), ('History'), ('Biology'), ('Chemistry'), ('Physics'), ('Computer Science'), ('Art'), ('Music'), ('Physical Education'), ('Geography'), ('Economics'), ('Psychology'), ('Philosophy'), ('Languages'), ('Engineering'); -- scores 테이블에 더미 데이터 삽입 INSERT INTO scores (student_id, subject_id, year, semester, score) WITH RECURSIVE cte (n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM cte WHERE n < 1000000 -- 생성하고 싶은 더미 데이터의 개수 ) SELECT FLOOR(1 + RAND() * 1000000) AS student_id, -- 1부터 1000000 사이의 난수로 학생 ID 생성 FLOOR(1 + RAND() * 16) AS subject_id, -- 1부터 16 사이의 난수로 과목 ID 생성 YEAR(NOW()) - FLOOR(RAND() * 5) AS year, -- 최근 5년 내의 임의의 연도 생성 FLOOR(1 + RAND() * 2) AS semester, -- 1 또는 2 중에서 랜덤하게 학기 생성 FLOOR(1 + RAND() * 100) AS score -- 1부터 100 사이의 랜덤한 점수 생성 FROM cte;
 
 
  1. 기존 SQL문 성능 조회해보기
    1. SELECT st.student_id, st.name, AVG(sc.score) AS average_score FROM students st JOIN scores sc ON st.student_id = sc.student_id GROUP BY st.student_id, st.name, sc.year, sc.semester HAVING AVG(sc.score) = 100 AND sc.year = 2024 AND sc.semester = 1;
      notion image
      약 4000ms 정도의 시간이 걸린다.
 
  1. 성능 개선해보기
    1. 우선 SQL문을 살펴보니 HAVING절에 굳이 있지 않아도 될 조건이 HAVING 절에 포함되어 있다. WHERE 문으로 옮길 수 있는 조건을 옮긴 뒤 성능을 다시 테스트해보자.
      SELECT st.student_id, st.name, AVG(sc.score) AS average_score FROM students st JOIN scores sc ON st.student_id = sc.student_id WHERE sc.year = 2024 AND sc.semester = 1 GROUP BY st.student_id, st.name HAVING AVG(sc.score) = 100;
      WHERE문으로 옮길 수 있는 조건을 옮기면서, 불필요한 GROUP BY 컬럼을 삭제했다.
       
      notion image
      450ms 정도로 성능이 향상됐다.
 
author
category
createdAt
series
비전공자도 이해할 수 있는 MySQL 성능 최적화 입문/실전 (SQL 튜닝편)
slug
type
series-footer
updatedAt
Dec 6, 2025 12:47 AM
📎
이 글은 비전공자도 이해할 수 있는 Docker 입문/실전 강의의 수업 자료 중 일부입니다.