[MySQL 쿼리 최적화] 실행 계획을 분석해보자

2026. 4. 2. 21:46·DB

현재 프로젝트에 남은 인덱스는 두 개이지만, DB 테이블에 남아있는 인덱스는 실험하면서 걸어둔 인덱스가 모두 남아있었다.

 

 

아래 쿼리는 현재 댓글 작성이 열려 있어서 댓글 작성이 진행되고 있는 게시글의 최신순 10건 조회 쿼리다.

이 쿼리는 지금 인덱스를 잘 타고 있을까?

 

 

 

 

  • 항상 주요 지표인 select_type, type, Extra를 잘 살펴보자. select_type은 SIMPLE type은 ref Extra에 Using where

 

해당 쿼리의 실행계획은 MySQL 서버에서 체크 조건(Using where)을 확인해주고 있긴 하지만 아주 효율적인 것을 알 수 있다. 어

어? 현재 인덱스 추가를 해 두지 않은 인덱스를 선택하고 있다.

 

내가 걸어놓은 Posts 테이블의 인덱스는 idx_is_completed_created_at과 idx_is_completed_id_created_at 두 개이다.

혹시나 예전에 인덱스 설계를 하면서 작성하고 코드에서만 삭제 했던 인덱스가 DB에서는 남아있을 수 있다고 생각해서 Posts의 인덱스 목록을 살펴보았다.

 

 

아래 명령어를 입력하면 해당 테이블에 존재하는 모든 인덱스를 조회할 수 있다.

 

 

사용하지 않는 인덱스는 모두 삭제해주자. 실무적으로는 invisible 설정을 하면 옵티마이저가 해당 인덱스를 사용하지 않는다. 사용하지 않는 것을 확인하면 삭제하도록 하자.

DROP INDEX 인덱스명 ON 테이블명;

 

 

 

 

 

 

테스트 겸 인덱스가 아닌 체크 조건으로 걸려있는 is_deleted를 빼고 테스트를 해봤는데,

MySQL 서버가 따로 체크조건을 필터링하지 않으니

책에서 읽은 것 처럼 Extra에 Using where이 바로 사라진다.

 

이런 곳에서 책 읽은 보람을 찾는 것 같다.

 

 

 

 

type 컬럼의 ref 접근 방법은 무려 4등이다. 이미 충분히 빠르다고 볼 수 있지만,

왜 ref 타입으로 접근하고 있는지 알아보고 혹여 인덱스가 잘못 걸려 있다면 개선해 나가보자.

 

 

<참고> 인덱스의 종류와 관계없이 동등(equal) 조건으로 검색할 때는 ref 접근 방법이 사용된다. ref 타입은 반환되는 레코드가 반드시 1건이라는 보장이 없으므로 const나 eq_ref보다는 빠르지 않다. 하지만 동등한 조건으로만 비교되므로 매우 빠른 레코드 조회 방법의 하나다.

 

 

 

ref 접근 방법의 설명을 읽어보고 쿼리문을 다시 읽어보면

explain select * from posts p where p.is_completed = false and p.is_deleted = false order by p.created_at desc limit 10;

현재 쿼리도 충분히 좋은 상태라는 것을 알 수 있다.

 

이유는 인덱스를 걸 때, 카디널리티가 높은 컬럼에 인덱스를 걸어야 효율이 좋은데 이 경우 뽑고 싶은 데이터는 ‘현재 완료 상태가 아닌데 소프트 딜리트 상태가 아니면서 생성일자가 최신인 데이터’이므로 소프트 딜리트 여부도 복합인덱스 컬럼으로 추가해주면 더 적합한 인덱스 설계라고 생각된다.

 

단, 고려할 점은 인덱스 키 길이가 그만큼 늘어난다는 점인데, 삭제 여부는 boolean 타입이므로 충분히 감안할 수 있다고 생각한다

따라서, 가장 많이 필터링 할 수 있는 것을 앞에서부터 (is_completed, is_deleted, created_at) 순서로 인덱스를 설계했다. 이제 성능을 비교해보자.

 

 

인덱스를 걸기 전은 아래와 같다.

 

 

 

 

인덱스를 건 후

두 인덱스 중 새로 만든 인덱스를 옵티마이저는 더 낫다고 선택했다.

 

 

 

그럼 성능은..?

 

 

 

 

사실, 성능 자체는 비슷하다. 이럴 경우 index의 key_length 를 is_deleted를 선택하지 않으면 더 줄일 수 있으니 둘 다 괜찮은 방법이라고 생각한다.

'DB' 카테고리의 다른 글

[MySQL] 버퍼풀과 innodb 버퍼풀 인스턴스 설정  (0) 2026.02.12
MySQL의 Using filesort와 Using temporary  (0) 2025.11.23
[이음] 프로젝트에 쿼리의 실행계획을 분석하며 최적화 해보기  (1) 2025.11.22
[DB] B+Tree 란? 그리고 자바 구현  (0) 2025.04.12
[DB] VACUUM vs GC ?! 데이터베이스 최적화의 첫 걸음  (0) 2025.04.05
'DB' 카테고리의 다른 글
  • [MySQL] 버퍼풀과 innodb 버퍼풀 인스턴스 설정
  • MySQL의 Using filesort와 Using temporary
  • [이음] 프로젝트에 쿼리의 실행계획을 분석하며 최적화 해보기
  • [DB] B+Tree 란? 그리고 자바 구현
dev_noonoo
dev_noonoo
인생의 스노우볼을 굴리는 개발자 누누(이재혁)의 블로그입니다.
이전 글
[MySQL] 버퍼풀과 innodb 버퍼풀 인스턴스 설정
2026.02.12
  • dev_noonoo
    개발자 누누님의 블로그
    dev_noonoo
  • 전체
    1,600
    오늘
    3
    어제
    2
    • 분류 전체보기 (35) N
      • 운영체제 (0)
      • 네트워크 (5)
      • DB (6) N
      • 코딩테스트 (0)
      • 아키텍처 (7)
      • 회고 (1)
      • 언어(java, kotlin, python ..... (5)
      • 우아한 테크코스 프리코스 (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
  • 공지사항

  • 인기 글

    • [우아한 테크코스 8기 백엔드]프리코스 1주차 회고 -문자⋯
      2025.10.21
    • 고성능 JPA & Hibernate / SQL 강의 추천
      2025.04.20
    • JSCODE 네트워크 스터디를 진행하며 느낀점들(feat.⋯
      2025.12.22
    • [클린 아키텍처] 웹 어댑터 구현하기 & 영속성 어댑터 구⋯
      2025.03.28
  • 태그

    분산락
    MySQL
    Using temporary
    filesort
    정렬방식
    redis
    좋아요api
  • 최근 댓글

    • 방문도장 찍어봅니다~
      new비비
      ·08.30
    • 들렸다 갑니다~
      문자life
      ·08.28
    • 들렸다 갑니다~
      문자life
      ·08.28
    • 왔다 갑니다.
      인포info
      ·08.26
    • 잘 보고갑니다~
      한달동안
      ·08.18
  • 최근 글

    • [MySQL 쿼리 최적화] 실행 계획을 분석해보자
      2026.04.02
    • [MySQL] 버퍼풀과 innodb 버퍼풀 인스턴스 설정
      2026.02.12
    • JSCODE 네트워크 스터디를 진행하며 느낀점들(feat.⋯
      2025.12.22
    • [컴퓨터 네트워크] 네트워크 레이어
      2025.12.15
    • [컴퓨터 네트워크] TCP & UDP
      2025.12.09
  • hELLO· Designed By정상우.v4.10.5
dev_noonoo
[MySQL 쿼리 최적화] 실행 계획을 분석해보자
상단으로

티스토리툴바