본 문서는 StartUP Tuning(for MySQL) 강의의 일부를 책의 서술 형태로 정리한 문서입니다.

 

지난 글에서는 SQL 성능 문제를 인덱스로 해결했습니다. ( https://sweetquant.tistory.com/555 )

인덱스를 마스터하기 위해서는 많은 시간과 노력이 필요합니다. 인덱스를 본격적으로 공부하기에 앞서 인덱스의 개념에 대해 간단히 알아볼 필요가 있습니다.


"데이터를 정렬해 라벨링하고, 라벨을 참고해 원하는 데이터를 빠르게 찾는다"
이것이 바로 인덱스의 개념입니다.

 

INDEX 개념잡기


DBMS: MySQL 8.0.35

SQL에 성능 문제를 해결하기 위해서 가장 먼저 할 일은 실행계획을 확인하는 것입니다.

실행계획을 통해 Table scan과 같은 테이블 전체를 검색하는 작업을 발견하면, 인덱스(INDEX)를 생성해 테이블 전체 검색이 아닌 인덱스를 이용한 데이터 검색으로 SQL이 처리되도록 유도할 수 있습니다.

그러나, 이러한 단순한 사실만 알고 인덱스를 적용해서는 SQL 성능 개선을 제대로 할 수 없습니다.

실제로 인덱스를 만들어도 성능 개선 효과가 없거나 오히려 역효과가 나는 경우도 있습니다.

인덱스를 통한 성능 개선 효과가 있는지 판단하기 위해서는 인덱스의 개념과 물리적인 구조도 이해하고 있어야 합니다.


[Tip]
느린 SQL의 성능 개선 방법에는 인덱스만 있는 것은 아닙니다. 인덱스는 다양한 성능 개선 방법을 익히기 위한 시작점일 뿐입니다.


 

우리는 가장 먼저 인덱스의 개념을 이해할 필요가 있습니다. 회사에 아래 그림 좌측과 같이 12개의 거래처가 있다고 가정해봅시다. 12개의 거래처 관련된 문서를 거래처 서류함에 보관하려고 합니다.


 
회사의 팀장이 ‘나엉망’ 직원에게 거래처 서류를 정리하라고 지시했습니다.

‘나엉망’ 직원은 빨리 정리하고 쉬기 위해서 무작위로 서류를 세 개씩 나누어서 서류함의 네 개 서랍에 나누어 넣었습니다. 무작위로 서류를 서랍에 넣었으므로 결과적으로 필요한 서류가 어느 서랍에 있는지는 알 수가 없게 되었습니다. 다시 말해, Airbnb 서류가 어느 서랍에 있을지는 알 수 없습니다. Airbnb 서류를 찾기 위해서는 서류함의 서랍을 하나씩 열어봐야 합니다. 운이 좋으면 첫 번째 서랍에서 찾을 수도 있고, 운이 나쁘면 네 번째 서랍에서 서류를 발견하게 될 것입니다. 다른 거래처의 서류도 마찬가지입니다. 그날의 운에 따라 서류를 빨리 찾거나 늦게 찾거나 하는 것이죠.


이러한 상황을 알게 팀장은 이번에는 ‘나깔끔’ 직원을 불러 서류를 다시 정리하라고 지시했습니다.

‘나깔끔’직원은 모든 서류를 꺼낸 후에 알파벳 순으로 정렬을 한 후에, 알파벳 순서대로 거래처를 세 개씩 나누고 서랍에 차례대로 넣었습니다. 그리고 서랍 앞에는 어떤 알파벳으로 시작하는 거래처 서류가 있는지 알아 볼 수 있도록 라벨링을 했습니다. 다음 그림과 같이 말이죠.

 


 

이와 같이 정리를 해 놓으니, 서랍을 한 번만 열면 원하는 서류를 찾을 수 있습니다. Airbnb는 (A)로 시작하므로 1번 서랍을 열면 바로 찾을 수 있습니다. Samsung 서류는 (N)과 (T) 사이에 있으므로 3번 서랍을 열만 바로 찾을 수 있습니다.
이처럼 데이터를 정렬하고 라벨링을 해서, 원하는 데이터를 빠르게 찾을 수 있도록 도움 주는 객체가 바로 인덱스입니다.

 

인덱스는 일반적으로 삼각형 모양으로 표현합니다. 서류함을 삼각형의 위쪽 꼭지점으로, 서랍 안에 들어가 있는 서류들을 삼각형의 밑면으로 표현할 수 있습니다. 아래 그림과 같이 말이죠.

 

인덱스는 실제 B Tree 자료 구조로 구현되어 있으며 B Tree에서의 데이터 검색을 효과적으로 설명하기 위해 이와 같은 이와 같은 삼각형 모양을 자주 사용하게 됩니다.


인덱스의 개념을 간단히 살펴봤습니다. 인덱스를 제대로 사용하기 위한 첫 단추를 잠근 것입니다. 인덱스를 마스터하기 위해서는 앞으로 인덱스의 구조도 알아야 하며, SQL에 따라 인덱스 탐색이 어떻게 되는지, 그리고 인덱스의 종류도 공부해야 합니다.
인덱스 개념만 공부한 채로 섣부르게 인덱스를 만들게 되면 큰 문제를 겪을 수 있습니다.

SQL 경력이 20년이 넘는 저 역시도 여전히 인덱스를 만드는 일은 항상 걱정이 앞서는 일이기도 합니다.

인덱스는 어떤 SQL의 성능에는 도움이 되기도 하지만, 어떤 SQL의 성능에는 악영향을 줄 수도 있기 때문입니다.

항상 인덱스 추가, 변경은 긴장되는 일이랍니다.

시간을 가지고 인덱스와 SQL의 성능에 대해 더 공부해보신후 인덱스 적용을 고민해보시기 바랍니다.

 

 

PDF 다운로드

20240429_StartUPTuning_인덱스개념.pdf
0.45MB


[StartUP Tuning]

 

StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문

「StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문」 < 일정 > 5/12(일), 5/19(일), 5/26(일) 오전 9시 ~ 오후 5시 (...

cafe.naver.com

 

[StartUP SQL]

 

StartUP SQL 소개 및 목차

SQL을 배우기 위한 최적의 시작점 StartUP SQL! 교육 슬라이드 전체를 블로그에 무료 오픈했습니다. (총 409장 슬라이드, 이미지로 게시) 아래 목차를 차례대로 하나씩 따라해보시기 바랍니다. 본인의

sweetquant.tistory.com

 

 

글 하단 부분에서 별도 pdf로 다운로드 받으실 수 있습니다.

 

MySQL의 EXPLAIN ANALYZE 읽어보기 #2

 

DBMS: MySQL 8.0.35

지난 글에서는 MySQL의 실제 실행계획을 살펴봤습니다.

https://sweetquant.tistory.com/553

 

MySQL EXPLAIN ANALYZE

MySQL의 EXPLAIN ANALYZE 읽어보기 테스트 DBMS: MySQL 8.0.35 본 문서는 StartUP Tuning(for MySQL) 강의의 일부를 책의 서술 형태로 정리한 문서입니다. 가장 아래에 PDF 버젼으로도 첨부드리니 필요하신 분은 다

sweetquant.tistory.com

 

그리고 지난 글 마지막에 SQL의 가장 큰 문제가 어디인지 스스로 진단해보기를 부탁드렸습니다. 지난 글에서 설명한 SQL과 실행계획은 다음과 같습니다.

EXPLAIN ANALYZE
SELECT T1.CUS_ID ,COUNT(*) CNT
FROM   T_ORD_BIG T1 
WHERE  T1.ORD_DT = STR_TO_DATE('20170103','%Y%m%d')
GROUP BY T1.CUS_ID;

1 -> Table scan on <temporary>  (actual time=5992..5992 rows=9 loops=1)
2     -> Aggregate using temporary table  (actual time=5992..5992 rows=9 loops=1)
3         -> Filter: (t1.ORD_DT = ('20170103')) (actual time=35.4..5985 rows=18000 loops=1)
4             -> Table scan on T1 (actual time=0.0889..5303 rows=6.09e+6 loops=1)



라인 번호 기준으로 4->3->2->1의 흐름으로 SQL이 처리되는데, 전체 실행 시간이 5.9초 정도입니다.

이 중에 4번과 3번 라인의 Table scan과 Filter가 대부분의 실행 시간을 차지하고 있습니다.

또한, 4번 단계에서 처리한 데이터 건수가 6.09e+6(6,090,000)이었으나 3번 단계에서 18,000건으로 매우 많이 줄어 든 것을 알 수 있습니다.

이러한 정보를 종합해 보면, 4번과 3번 단계를 처리하는 과정이 성능 문제의 중심이란 것을 알 수 있습니다.

 

어디가 아픈지는 알았으니 이제 치료를 해야 하는데, 치료를 하기 위해서는 기본적인 치료법을 알고 있어야 합니다.

아픈 SQL을 치료하는 방법은 매우 다양합니다.

그 중에 Table scan(TABLE FULL SCAN)이란 질병이 있는 SQL은 인덱스(INDEX)라는 처방이 필요합니다.

이 인덱스란 치료를 처방하기 위해서는 인덱스의 구조와 인덱스를 이용해 데이터를 찾는 과정에 대한 지식이 필요합니다.

이는 별도로 길게 다루어야 할 내용입니다. 그러므로 지금은 인덱스를 만들어 효과가 있는지 정도만 살펴보도록 하겠습니다.

SQL을 보면 WHERE 절에 ORD_DT에 대한 조건이 있습니다. 그리고 실행계획의 3번 라인을 살펴보면 Filter 조건으로 ORD_DT가 사용되고 있습니다. 이는 실행계획에서 Filter 부분이 SQL의 WHERE 절을 처리한 것이라는 뜻입니다. 인덱스는 기본적으로 Filter된 컬럼에 대해 구성합니다.

아래 SQL로 인덱스를 추가합니다.

CREATE INDEX T_ORD_BIG_X01 ON T_ORD_BIG(ORD_DT);

 


[Tip]
인덱스를 만드는 작업은 DB내 자원을 제법 사용합니다. 해당 테이블에 부하가 걸리기도 합니다. 실제 인덱스를 만들어본 경험이 없으신 분은 개발 DB에서 충분한 테스트를 해보기 바랍니다. 운영 DB에서 인덱스를 만들 때는 사용자가 가장 적은 시간을 이용하는 것을 권장합니다.



인덱스를 만들고, 이전 SQL을 다시 실행해 실제 실행계획을 추출해봅니다. 아래와 같습니다.

EXPLAIN ANALYZE
SELECT T1.CUS_ID ,COUNT(*) CNT
FROM   T_ORD_BIG T1 
WHERE  T1.ORD_DT = STR_TO_DATE('20170103','%Y%m%d')
GROUP BY T1.CUS_ID;

1 -> Table scan on <temporary>  (actual time=38.2..38.2 rows=9 loops=1)
2    -> Aggregate using temporary table  (actual time=38.2..38.2 rows=9 loops=1)
3      -> Index lookup on T1 using T_ORD_BIG_X01 (ORD_DT= '20170103') (actual time=0.521..26.1 rows=18000 loops=1)

 

인덱스를 만들어준 것만으로 기존 5.9초였던 실행 시간이 0.038초로 개선되었습니다.

실행계획을 살펴보면 네 개의 단계였던 실행계획이 세 개의 단계로 줄어든 것을 알 수 있습니다.

주의 깊게 볼 것은 3번 라인의 Index Lookup입니다. 이전 실행계획에 있던 Table scan과 Filter가 사라지고 Index Lookup이 나타났습니다. Index Lookup은 WHERE 절의 동등(=) 조건에 해당하는 데이터를 인덱스를 사용해 찾아낸 경우에 나타나는 작업입니다.

Index Lookup의 actual 항목을 살펴보면 처리한 시간이 0.521..26.1ms로 매우 작습니다. 또한 인덱스로 처리한 건수(rows)가 18,000 건으로 SQL 결과를 얻어내는데 필요한 만큼의 데이터만 읽은 것입니다.

다시 말해, 불필요한 데이터에 대한 접근 없이 SQL이 처리된 것입니다.

 

이처럼 인덱스가 없는 SQL은 인덱스를 만드는 것만으로 성능 개선 효과가 나타날 수 있습니다.

물론 무조건 인덱스를 만든다고 성능 개선이 되는 것은 아닙니다. 경우에 따라서는 생성한 인덱스가 아무 효과가 없을 수도 있으며, 오히려 역효과가 날 수도 있습니다.

 

인덱스는 SQL 성능 개선을 위한 많은 방법 중에 하나입니다.

앞에서도 설명 드렸듯이 SQL의 성능 문제를 해결하기 위해 가장 먼저 할 일은 실행계획을 살펴보는 것입니다.

실행계획으로 현재 아픈 곳을 찾아내 진단하고, 현재 SQL과 테이블 구조(현재 인덱스, 컬럼 구성, 데이터 양, 테이블 간의 관계 등)를 고민해 그에 맞는 적절한 진료를 해야 합니다.


오늘 준비한 글은 여기까지입니다. 감사합니다.

 

아래는 실제 강의에서 해당 과정을 설명하는 슬라이드입니다.

 

 

 

아래는 현재 글을 pdf로 만든 자료입니다.

20240429_StartUPTuning_실행계획2.pdf
0.33MB

 

 


[StartUP Tuning]

  • SQL 입문을 넘어선 MySQL을 활용한 SQL 튜닝 입문 교육
  • 2024년 5월 주말 오프라인 교육 과정을 모집중: https://cafe.naver.com/dbian/7717
 

StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문

「StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문」 < 일정 > 5/12(일), 5/19(일), 5/26(일) 오전 9시 ~ 오후 5시 (...

cafe.naver.com

[StartUP SQL]

 

StartUP SQL 소개 및 목차

SQL을 배우기 위한 최적의 시작점 StartUP SQL! 교육 슬라이드 전체를 블로그에 무료 오픈했습니다. (총 409장 슬라이드, 이미지로 게시) 아래 목차를 차례대로 하나씩 따라해보시기 바랍니다. 본인의

sweetquant.tistory.com

 

MySQL을 활용한 SQL 튜닝 입문. StartUP Tuning의 24년 5월 교육 교재의 목차를 소개합니다.

이번에도 375장의 슬라이드로 두툼한 두께를 자랑합니다. 이 중에 BOOSTER QUIZ는 46개입니다.

교육 수강생 분들께 제본 교재를 제공해드립니다.

(제본 교재는 A4 한 페이지에 두 개의 슬라이드로 구성되어 있습니다.)

 

MySQL의 성능 개선을 위한 첫 걸음, StartUP Tuning으로 시작해보시기 바랍니다.

 - 교육 신청: https://cafe.naver.com/dbian/7717

 

StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문

「StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문」 < 일정 > 5/12(일), 5/19(일), 5/26(일) 오전 9시 ~ 오후 5시 (...

cafe.naver.com

 

주목차

1. 강의 소개
2. 실습환경 구성(MySQL)
3. 실습환경 구성(Maria)
5. 성능 기본 지식
6. 실행계획
7. INDEX 1
8. INDEX 2
9. INDEX와 성능 1
10. INDEX와 성능 2
11. INDEX와 성능 3
12. ORDER BY
13. JOIN의 내부 처리 방식
14. HINT
15. JOIN과 성능
16. 맛보기 튜닝
17. Paging SQL
18. INDEX 설계
19. 성능 수집
20. 파티션
21. Transaction
22. SQL GUIDE

 

상세 목차

1. 강의 소개
    1. ERD: MYTUNDB 논리(Logical)
    1. ERD: MYTUNDB 물리(Physical)
    1. 강사 소개
    1. DBian 도서 소개
    1. StartUP Tuning
    1. 차례
2. 실습환경 구성(MySQL)
    2. 완성된 실습 환경
    2. MySQL 다운로드
    2. MySQL 다운로드: Windows MySQL 8.0.35
    2. MySQL 다운로드: MAC MySQL 8.0.35 다운로드
    2. 기존 MySQL Upgrade / Remove 선택
    2. Choosing a setup Type
    2. Check Requirements
    2. Installation
    2. Product Configuration / Type and Networking
    2. Authentication Method / Accounts and Roles
    2. Windows Service / Server File Permissions
    2. Apply Configuration
    2. MySQL Router Configuration / Connect To Server
    2. Apply Configuration
    2. Installation Complete
    2. Workbench 접속 #1
    2. Workbench 접속 #2
    2. Workbench 접속 #3
    2. Hello SQL
    2. Workbench 필요한 환경 설정 #1
    2. Workbench 필요한 환경 설정 #2
    2. Dbeaver
    2. SQL Tool
3. 실습환경 구성(Maria)
    3. 다운로드
    3. 완성된 실습 환경
    3. MariaDB 설치
    3. HeidiSQL
    3. Dbeaver
    3. Hello SQL
    4. 실습 데이터베이스 생성
    4. CREATE DATABASE
    4. 기본 데이터베이스 설정
    4. 캐릭터셋 확인
    4. 테이블 및 데이터 생성
5. 성능 기본 지식
    5. SQL 튜닝이란?
    5. SQL 성능 개선의 주요 요소
    5. 비효율 SQL이란?
    5. SQL 처리 과정
    5. Execution Plan과 Optimizer #1
    5. Execution Plan과 Optimizer #2
    5. Execution Plan과 Optimizer #3
    5. Statistics #1
    5. Statistics #2
    5. Statistics #3
    5. Storage Engine
    5. Oracle VS. MySQL
    5. IO
    5. 물리적 IO와 논리적 IO #1
    5. 물리적 IO와 논리적 IO #2
    5. Buffer pool size 변경하기
    5. SQL 성능 개선 프로세스
    5. 지속적인 SQL 성능 개선 필요성
6. 실행계획
    6. 인덱스 초기화
    6. EXPLAIN
    6. EXPLAIN 이해하기
    6. EXPLAIN 이해하기 – select_type
    6. EXPLAIN 이해하기 – 실행계획의 흐름 해석하기
    6. EXPLAIN 이해하기 – type(데이터 접근방식)
    6. EXPLAIN – Extra(옵티마이져 동작방식) 이해하기
    6. EXPLAIN FORMAT
    6. EXPLAIN FORMAT = TREE (MySQL)
    6. 실행한 SQL의 실제 접근 데이터 건수 측정
    6. 실행한 SQL의 요청 논리적IO 측정
    6. ANALYZE SQL(MariaDB)
    6. EXPLAIN ANALYZE #1 (MySQL)
    6. EXPLAIN ANALYZE #2 (MySQL)
    6. PROFILING
    6. 다른 세션의 실행계획 확인 (MySQL)
    BOOSTER QUIZ 6-1
7. INDEX 1
    7. INDEX란? 우선 읽어보자!
    7. 실행계획의 비효율을 찾아 INDEX로 해결하기 #1
    7. 실행계획의 비효율을 찾아 INDEX로 해결하기 #2
    7. 실행계획의 비효율을 찾아 INDEX로 해결하기 #3
    7. INDEX의 생성과 삭제
    7. INDEX 개념 잡기 #1
    7. INDEX 개념 잡기 #2
    7. B-Tree INDEX #1
    7. B-Tree INDEX #2
    7. 테이블 구조
    7. Heap 구조와 Table Scan(TABLE FULL SCAN)
    7. Heap과 INDEX #1
    7. Heap과 INDEX #2
    7. Heap과 INDEX #3
    7. Heap과 INDEX #4
    7. Heap과 INDEX #5
    7. 인덱스는 삼각형으로
    7. 인덱스 탐색 과정의 시각화 #1
    7. 인덱스 탐색 과정의 시각화 #2: CUS_ID 인덱스를 사용한 데이터 검색
    7. 인덱스 직접 그려보기
    7. CLUSTERED (INDEX) #1
    7. CLUSTERED (INDEX) #2
    7. CLUSTERED (INDEX) #3
    7. HEAP VS. CLUSTERED #1
    7. HEAP VS. CLUSTERED #2
8. INDEX 2
    8. 데이터 접근 방법
    8. 인덱스를 이용한 데이터 접근 #1
    8. 인덱스를 이용한 데이터 접근 #2: 인덱스 접근 시각화
    8. 인덱스를 이용한 데이터 접근 #3: INDEX LOOKUP
    8. 인덱스를 이용한 데이터 접근 #4: INDEX RANGE SCAN
    8. 인덱스를 이용한 데이터 접근 #5: COVERING INDEX (LOOKUP/RANGE SCAN)
    8. 인덱스를 이용한 데이터 접근 #6: INDEX SCAN(INDEX FULL SCAN)
    8. 인덱스를 이용한 데이터 접근 #7: 정리
    8. 테이블(클러스터드) 접근 #1
    8. 테이블(클러스터드) 접근 #2: 검색양에 따른 성능 변화
    8. 테이블(클러스터드) 접근 #3: 테이블 접근 횟수에 따른 성능 변화
    8. 테이블(클러스터드) 접근 #4: Covering Index
    8. 테이블(클러스터드) 접근 #5: 클러스터드 인덱스를 이용한 검색
    8. INDEX 확인하기 #1
    8. INDEX 확인하기 #2
    8. CLUSTERD INDEX에 대한 고민
    8. InnoDB가 제공하는 INDEX 구조
    8. INDEX 분류
    8. 조건에 따른 인덱스 선택
    BOOSTER QUIZ 8-1
    BOOSTER QUIZ 8-2
    BOOSTER QUIZ 8-3
    BOOSTER QUIZ 8-4
    BOOSTER QUIZ 8-5
9. INDEX와 성능 1
    9. 어느 컬럼에 인덱스를 만들 것인가? #1
    9. 어느 컬럼에 인덱스를 만들 것인가? #2
    9. 어느 컬럼에 인덱스를 만들 것인가? #3
    9. 어느 컬럼에 인덱스를 만들 것인가? #4: RNO를 제외한 조건은 어디서 처리되는가?
    BOOSTER QUIZ 9-1
    BOOSTER QUIZ 9-2
    BOOSTER QUIZ 9-3
    9. 공식만 외우지 말자 #1
    9. 공식만 외우지 말자 #2
10. INDEX와 성능 2
    10. 단일 인덱스 VS. 복합 인덱스 #1
    10. 단일 인덱스 VS. 복합 인덱스 #2
    10. 단일 인덱스 VS. 복합 인덱스 #3
    10. 단일 인덱스 VS. 복합 인덱스 #4
    10. 단일 인덱스 VS. 복합 인덱스 #5
    10. 단일 인덱스 VS. 복합 인덱스 #6: 오라클의 실행계획
    BOOSTER QUIZ 10-1
    10. 복합 인덱스의 컬럼 순서
    10. 복합 인덱스 컬럼 순서에 따른 성능 차이 #1
    10. 복합 인덱스 컬럼 순서에 따른 성능 차이 #2
    10. 복합 인덱스 컬럼 순서에 따른 성능 차이 #3
    10. 복합 인덱스 컬럼 순서에 따른 성능 차이 #4
    BOOSTER QUIZ 10-2
    BOOSTER QUIZ 10-3
    BOOSTER QUIZ 10-4
    10. 복합 인덱스의 선두 조건 누락
    10. 복합 인덱스 컬럼 선정과 순서 #1
    10. 복합 인덱스 컬럼 선정과 순서 #2
    10. 복합 인덱스 컬럼 선정과 순서 #4
    BOOSTER QUIZ 10-5
    BOOSTER QUIZ 10-6
    BOOSTER QUIZ 10-7
    BOOSTER QUIZ 10-8
    10. 복합 인덱스 정리
11. INDEX와 성능 3
    11. 인덱스를 제대로 활용할 수 없는 SQL #1
    11. 인덱스를 제대로 활용할 수 없는 SQL #2
    BOOSTER QUIZ 11-1
    BOOSTER QUIZ 11-2
    11. Index Covering(Covered Index) #1
    11. Index Covering(Covered Index) #2
    BOOSTER QUIZ 11-3
    11. 복합 인덱스의 선두 조건 누락 #1
    11. 복합 인덱스의 선두 조건 누락 #2
    11. 복합 인덱스의 선두 조건 누락 #3
    11. 복합 인덱스의 선두 조건 누락 #4 – Index Skip Scan
    BOOSTER QUIZ 11-4
    11. 언제까지 인덱스를 탈 것만 같아? #1
    11. 언제까지 인덱스를 탈 것만 같아? #2
    11. 언제까지 인덱스를 탈 것만 같아? #3
    11. 너무 많은 인덱스의 위험성
    11. 클러스터드 인덱스의 크기
    11. INDEX란? 한 번 더 읽어보자!
    BOOSTER QUIZ 11-5
12. ORDER BY
    12. 비효율 찾기
    12. Using filesort
    12. Using filesort 제거하기
    12. sort buffer size
    12. INDEX RANGE SCAN - ASC
    12. INDEX RANGE SCAN - DESC
    12. INDEX RANGE SCAN – 정렬과 무관하게 인덱스를 사용하면?
    12. ORDER BY LIMIT n
    12. ORDER BY SQL을 위한 인덱스 전략 #1
    12. ORDER BY SQL을 위한 인덱스 전략 #2
    12. ORDER BY SQL을 위한 인덱스 전략 #3
    BOOSTER QUIZ 12-1
    BOOSTER QUIZ 12-2
13. JOIN의 내부 처리 방식
    13. JOIN의 내부 처리 방식
    13. NL JOIN 이해하기 #1
    13. NL JOIN 이해하기 #2
    13. HASH JOIN 이해하기 #1
    13. HASH JOIN 이해하기 #2
    13. HASH JOIN 이해하기 #1 (MariaDB)
    13. HASH JOIN 이해하기 #2 (MariaDB)
    13. HASH JOIN 이해하기 #3 (MariaDB)
    13. HASH JOIN 이해하기 #4 (MariaDB)
    13. HASH JOIN 이해하기 #1 (MySQL)
    13. HASH JOIN 이해하기 #2 (MySQL)
    BOOSTER QUIZ 13-1
    BOOSTER QUIZ 13-2
14. HINT
    14. Optimizer Hints
    14. 인덱스 힌트
    14. JOIN_ORDER #1
    14. JOIN_ORDER #2
    14. JOIN_ORDER 와 JOIN 방법 제어
15. JOIN과 성능
    15. NL JOIN 튜닝 – 선행접근과 후행접근
    15. NL JOIN 튜닝 – 후행접근 조인 컬럼의 인덱스 유무 #1
    15. NL JOIN 튜닝 – 후행접근 조인 컬럼의 인덱스 유무 #2
    15. NL JOIN 튜닝 – 후행접근 조인 컬럼의 인덱스 유무 #4
    15. NL JOIN 튜닝 – 후행접근 조인 컬럼의 인덱스 유무 #4
    15. NL JOIN 튜닝 – 후행접근 조인 컬럼의 인덱스 유무 #5
    15. NL JOIN 튜닝 – 후행접근 조인 컬럼의 인덱스 유무 #6
    15. NL JOIN 튜닝 – 후행접근 조인 컬럼의 인덱스 유무 #7
    15. NL JOIN 튜닝 – join_cache_level (MariaDB)
    BOOSTER QUIZ 15-1
    BOOSTER QUIZ 15-2
    15. NL JOIN 튜닝 – 조인 순서 #1
    15. NL JOIN 튜닝 – 조인 순서 #2
    15. NL JOIN 튜닝 – 조인 순서 #3
    15. NL JOIN 튜닝 – 조인 순서 #4
    15. NL JOIN 튜닝 – 조인 순서 #5
    BOOSTER QUIZ 15-3
    15. NL JOIN 튜닝 – 여러 테이블의 조인 #1
    15. NL JOIN 튜닝 – 여러 테이블의 조인 #2
    15. NL JOIN 튜닝 – 여러 테이블의 조인 #3
    15. NL JOIN 튜닝 – 여러 테이블의 조인 #4
    15. HASH JOIN 튜닝 – Build Input 선택 #1 (MariaDB)
    15. HASH JOIN 튜닝 – Build Input 선택 #2 (MariaDB)
    15. HASH JOIN 튜닝 – Build Input 선택 #1 (MySQL)
    15. HASH JOIN 튜닝 – Build Input 선택 #2 (MySQL)
    15. HASH JOIN 튜닝 – 인덱스
    BOOSTER QUIZ 15-4
    BOOSTER QUIZ 15-5
    15. JOIN과 성능 Summary

16. 맛보기 튜닝
    16. 특정 고객의 마지막 주문 일자 구하기 #1
    16. 특정 고객의 마지막 주문 일자 구하기 #2
    16. 특정 고객의 마지막 주문 일자 구하기 #3
    BOOSTER QUIZ 16-1
    16. 여러 고객의 마지막 주문 일자: 서브쿼리 #1
    16. 여러 고객의 마지막 주문 일자: 서브쿼리 #2
    16. 불필요한 카운트
    16. Materialize #1
    16. Materialize #2: SQL 변경과 NO_MERGE
    16. Materialize #3: SQL 변경
    BOOSTER QUIZ 16-2
    16. 무리한 스칼라 서브쿼리
    BOOSTER QUIZ 16-3
    16. WHERE 절 서브쿼리의 순환조건 #1
    16. WHERE 절 서브쿼리의 순환조건 #2
    16. WHERE 절 서브쿼리의 순환조건 #3
    BOOSTER QUIZ 16-4
    16. WHERE 절 서브쿼리의 순환조건: 마지막 데이터 & 빅 테이블 #1
    16. WHERE 절 서브쿼리의 순환조건: 마지막 데이터 & 빅 테이블 #2
    BOOSTER QUIZ 16-5
    BOOSTER QUIZ 16-6
    16. QUERY TRANSFORMATION
    16. 조건 공급 #1
    16. 조건 공급 #2
    16. 조건 공급 #3
    16. 조건 공급 #4
    16. 적절하지 않은 조건 공급
    BOOSTER QUIZ 16-7
    BOOSTER QUIZ 16-8
    16. MySQL의 강력한 무기 Using index for group by #1
    16. MySQL의 강력한 무기 Using index for group by #2
    16. MySQL의 강력한 무기 Using index for group by #3
    16. MySQL의 강력한 무기 Using index for group by #4
    16. MySQL의 강력한 무기 Using index for group by #5
    BOOSTER QUIZ 16-9
    BOOSTER QUIZ 16-10
    BOOSTER QUIZ 16-11
    16. 날짜 테이블 #1
    16. 날짜 테이블 #2
    16. 날짜 테이블 #3
    BOOSTER QUIZ 16-12
    16. 값의 분포도를 생각하자 #1
    16. 값의 분포도를 고려 #2
    16. 조인을 추가한 복합 인덱스 활용 #1: 날짜 조건 누락(개선 전)
    16. 조인을 추가한 복합 인덱스 활용 #2 : 날짜 조건 누락(개선 후)
    16. 조인을 추가한 복합 인덱스 활용 #1: 회원ID 누락(개선 전)
    16. 조인을 추가한 복합 인덱스 활용 #2: 회원ID 누락(개선 후)
17. Paging SQL
    17. 페이징의 종류
    17. WAS 페이징
    17. DB 페이징 #1
    17. DB 페이징 #2
    17. DB-INDEX 페이징 #1
    17. DB-INDEX 페이징 #2
    17. DB-INDEX 페이징 #3
    17. DB-INDEX 페이징 #4
    17. 조인 SQL의 DB-INDEX 페이징 #1
    17. 조인 SQL의 DB-INDEX 페이징 #2
    17. DB-INDEX 페이징 유지의 어려움
    BOOSTER QUIZ 17-1
    BOOSTER QUIZ 17-1
18. INDEX 설계
    18. INDEX 설계
    18. INDEX 설계 과정
    BOOSTER QUIZ 18-1
19. 성능 수집
    19. SLOW Query 설정
    19. Performance Schema
    19. 성능 관련 주요 VIEW
20. 파티션
    20. 파티션 개념 #1
    20. 파티션 개념 #2
    20. 파티션 개념 #3
    20. 파티션 개념 #3
    20. 파티션 만들기
    20. 파티션 성능 #1
    20. 파티션 성능 #2
    20. 파티션 성능 #3
21. Transaction
    21. Transaction
    21. ACID
    21. Isolation level
    21. MySQL과 MariaDB의 기본 Isolation level
    21. Isolation level 변경하기
    21. AUTO COMMIT
    21. 테스트 테이블 생성
    21. WAIT 테스트 #1
    21. WAIT 테스트 #2
    21. WAIT 테스트 #3
    21. 출금 테스트 #1
    21. 출금 테스트 #2
    21. 출금 테스트 #3
    21. 출금 테스트 #4
    21. Manual Commit 과 MetadataLock
    21. Isolation Level에 따른 테스트 #1
    21. Isolation Level에 따른 테스트 #2
22. SQL GUIDE
    22. SQL GUIDE의 목적
    22. 필수 SQL GUIDE - 01
    22. 필수 SQL GUIDE - 02
    22. 필수 SQL GUIDE - 03
    22. 필수 SQL GUIDE - 04
    22. 필수 SQL GUIDE - 05
    22. 필수 SQL GUIDE - 06
    22. 필수 SQL GUIDE - 07
    22. 필수 SQL GUIDE - 08
    22. 필수 SQL GUIDE - 09
    22. 필수 SQL GUIDE - 10
    22. 필수 SQL GUIDE - 11
    22. 필수 SQL GUIDE - 12
    22. 필수 SQL GUIDE - 13
    22. 권장 SQL GUIDE - 01
    22. 권장 SQL GUIDE - 02
    22. 권장 SQL GUIDE - 03
    22. 권장 SQL GUIDE - 04
    22. 권장 SQL GUIDE - 05
    22. 권장 SQL GUIDE - 06
    22. 권장 SQL GUIDE - 07
    22. 권장 SQL GUIDE - 08
    22. 권장 SQL GUIDE - 09
    22. 권장 SQL GUIDE - 10
    22. 권장 SQL GUIDE - 11

 

 

 

 

MySQL의 EXPLAIN ANALYZE 읽어보기

 

테스트 DBMS: MySQL 8.0.35

 

본 문서는 StartUP Tuning(for MySQL) 강의의 일부를 책의 서술 형태로 정리한 문서입니다. 가장 아래에 PDF 버젼으로도 첨부드리니 필요하신 분은 다운 받아가시기 바랍니다.

 


SQL의 성능에 문제가 있을 때 우리가 가장 먼저 할 일은 실행계획을 살펴보는 것입니다. MySQL은 8버전부터 EXPLAIN ANALYZE 기능을 지원합니다. EXPLAIN ANALYZE는 “실제 실행된” SQL의 실행계획을 Tree 형태로 보여줍니다. 실제 실행계획은 SQL 성능 개선할 때 매우 유용한 기능입니다.
아래 SQL은 T_ORD_BIG 테이블에서 특정 일자의 데이터를 조회해 고객ID(CUS_ID)별 주문 건수를 구하는 SQL입니다. EXPLAIN ANALYZE를 사용했으므로 SQL의 실행 결과가 아닌 SQL을 처리한 과정에 해당하는 실행계획을 결과로 얻을 수 있습니다.

EXPLAIN ANALYZE
SELECT T1.CUS_ID ,COUNT(*) CNT
FROM   T_ORD_BIG T1 
WHERE  T1.ORD_DT = STR_TO_DATE('20170103','%Y%m%d')
GROUP BY T1.CUS_ID;

 

위 SQL을 실행하면 약 5.9초 정도의 시간이 걸리며, 아래와 같은 실제 실행계획이 출력됩니다. (지면상 실행계획의 일부 내용은 생략했습니다.)

-> Table scan on <temporary>  (actual time=5992..5992 rows=9 loops=1)
    -> Aggregate using temporary table  (actual time=5992..5992 rows=9 loops=1)
        -> Filter: (t1.ORD_DT = ('20170103')) (actual time=35.4..5985 rows=18000 loops=1)
            -> Table scan on T1 (actual time=0.0889..5303 rows=6.09e+6 loops=1)

 

Tree 형태의 실행계획은 일반적으로 가장 최하위 자식(Child) 단계부터 부모(Parent) 단계로 가면서 처리가 됩니다. 그러므로 위 실행계획의 흐름은 4->3->2->1 순서가 됩니다.

 


[Tip]
실행계획은 SQL의 내부적인 처리 흐름을 보여줄 뿐, 실제 DB 내부적인 처리 순서를 완벽하게 표현해주지는 않습니다.
4->3->2->1이란 순서가 4가 완료된 후 3이 실행되고, 3이 완료되면 2가 실행된다고 말하기는 어렵습니다.
4가 완료된 후 3이 처리되었을 수도 있으며, 4가 처리되면서 3이 동시에 처리될 수도 있습니다.
실행계획을 통해 내부적인 처리 순서를 완벽히 파악하기 보다는 전반적인 흐름을 이해하는 것에 초점을 맞추는 것이 좋습니다.


 

실행 계획의 처리 흐름대로 따라가면서 각 단계를 하나씩 살펴보도록 하겠습니다

 

4번 라인: Table scan on T1

가장 첫 번째 단계인 4번 라인을 보면, Table scan이란 작업이 실행되고 있습니다.

Table scan이란 테이블 전체를 검색하는 것을 뜻합니다. 테이블에 1억 건이 있다면 1억 건 전부를, 10억 건이 있다면 10억 건 전부를 검색했음을 뜻합니다.

Table scan 뒤에는 대상 테이블의 별칭이 적혀 있습니다.

현재 실행계획에는 Table scan on T1 이라고 표시되어 있습니다. 실행한 SQL의 FROM 절에서 T_ORD_BIG에 T1이란 별칭을 사용했습니다. 그러므로 Table scan의 대상이 T_ORD_BIG임을 알 수 있습니다.

감사하게도 실제 실행계획에는 해당 단계별로 수행된 시간과 처리한 건수의 정보를 actual 항목에 표시해 줍니다. 이와 같은 실제 처리된 정보는 SQL 튜닝에 매우 유용합니다. 4번 라인의 Table scan의 actual 정보는 다음과 같습니다.

  • Table scan on T1 (actual time=0.0889..5303 rows=6.09e+6 loops=1)

actual의 time 부분을 살펴보면 0.0859..5303로 표시되어 있습니다.

이는 해당 단계가 0.0859ms에 시작해 5303ms에 종료되었음을 뜻합니다. 5303ms는 약 5.3초입니다. 위 SQL은 총 실행 시간이 5.9초 정도가 걸립니다. 그 중에 4번 라인의 Table scan이 5.3초로 대부분을 차지하고 있는 상황입니다.

actual 항목 중에 rows 부분도 주의 깊게 살펴봐야 합니다. rows는 해당 단계가 끝났을 때 추출된 실제 데이터 건수입니다.

여기에는 6.09e+6이라고 표시되어 있습니다. 이는 과학적 표기법(또는 지수 표기법) 형태의 수치로서 구글이나 GPT를 통해 일반적인 숫자로 환산해보면 6,090,000 입니다. 다시 말해 Table scan 단계에서 추출된 데이터는 6,090,000 건입니다.

이 수치는 정확히 T_ORD_BIG의 현재 데이터 건 수와 일치합니다. Table Scan에서 테이블 전체 데이터를 읽었다는 것을 알 수 있으며, 이 과정이 5.3초 정도가 걸렸음을 알 수 있습니다.

 


3번 라인: Filter

Table scan을 거쳐 다음 실행되는 단계는 3번 라인의 Filter입니다. Filter는 특정 조건을 사용해 데이터를 걸러내는 처리를 하는 작업입니다.

MySQL의 Filter 단계에는 Filter로 사용된 조건이 같이 표시됩니다. 3번 라인의 실행계획을 통해 ORD_DT 조건에 대해 Filter가 처리된 것을 알 수 있습니다.

  • Filter: (t1.ORD_DT = ('20170103')) (actual time=35.4..5985 rows=18000 loops=1)

 

actual 항목을 보면 time 부분이 35.4..5985입니다. 35.4ms에 시작해 5985ms에 해당 단계가 완료되었습니다. 처리되는 시간대가 4번 단계의 Table scan과 겹치는 것으로 보아 3번과 4번이 동시에 처리되는 작업임을 유추할 수 있습니다. 실제로도 테이블의 데이터를 검색하면서 Filter 작업이 동시에 이루어집니다. 다만, MySQL의 Tree 실행계획에서는 별도 단계로 표시해준 것입니다. 다른 DBMS의 경우는 3번과 4번 단계를 하나의 단계로 표현해주기도 합니다.

3번 단계의 rows를 보면 18,000입니다. 4번 단계의 rows는 6,090,000이었습니다. 4번->3번 흐름으로 SQL이 처리되므로 6,090,000 건의 데이터에 접근해 결과적으로 18,000 건만 남았다고 해석할 수 있습니다. 이를 역산해보면 6,072,000 건((6,090,000-18,000)의 데이터가 4번에서 3번 단계를 거치면서 버려진 것입니다. 버려졌다는 것은 SQL 결과를 만드는데 불필요하다는 뜻입니다.

그러므로 이러한 불필요한 접근을 줄일 수 있다면 SQL 성능이 개선될 수 있습니다. 이는 다음 번에 이야기하기로 하고 계속해서 실행계획을 읽어 나가도록 하겠습니다.

 

2번 라인: Aggregate

2번 라인의 Aggregate는 데이터를 집계 처리하는 작업입니다.

  • Aggregate using temporary table  (actual time=5992..5992 rows=9 loops=1)

 

현재 우리가 실행한 SQL에는 “GROUP BY T1.CUS_ID”가 포함되어 있습니다. 그러므로 DB 내부적으로 Aggregate 작업을 거쳐 집계된(GROUP BY) 결과를 만들어냅니다. actual 항목의 time을 보면  5992..5992로 5.9초에 시작해 5.9초에 끝난 것을 알 수 있습니다. 시작과 종료 시간이 0.000초로 매우 빨리 처리된 것입니다.

Aggregate를 거쳐 만들어진 결과 건수는 9입니다. actual의 rows를 보면 알 수 있습니다. Aggregate의 결과는 9건이지만, Aggregate를 수행한 대상 건수는 몇 건일까요? 바로 이전 실행 단계인 3번 라인의 Filter의 rows에 그 정답이 있습니다. 3번 라인의 Filter의 rows는 18,000 이었습니다. 그러므로 18,000 건의 데이터가 Aggregate 작업으로 공급되었으며, 18,000 건의 데이터를 집계해 9 건의 결과를 만든 것입니다.

이처럼 rows 항목은 이전 단계와 비교해 보는 것이 좋습니다. 각 실행 단계를 거치면서 데이터 양이 어떻게 변하는지 추적할 수 있으며, 이를 통해 과도한 데이터 흐름이 있는 단계를 찾아낼 수 있습니다.


1번 라인: Table scan on <temporary>

1번 라인의 처리 내용을 살펴보면 4번 라인과 마찬가지로 Table scan을 하고 있습니다.

  • Table scan on <temporary>  (actual time=5992..5992 rows=9 loops=1)

다만 1번 라인의 Table scan 대상은 <temporary>라는 임시 테이블입니다. 이 임시 테이블은 2번 라인의 Aggregate를 거쳐 내부적으로 만들어진 테이블입니다. Aggregate 단계에서 9건의 데이터가 만들어졌으므로 <temporary>에는 당연히 9 건의 데이터만 담겨 있습니다. 9건의 데이터를 Table scan하는 작업은 매우 빠릅니다.

사실 실행 계획의 가장 마지막 단계는 SQL의 최종 결과를 단순 출력하는 단계로 대부분의 경우 주의 깊게 볼 필요는 없습니다.

 

지금까지의 내용을 기억하면서 아래 SQL과 실행계획을 다시 한번 꼼꼼하게 살펴보시기 바랍니다. 어느 부분이 현재 SQL의 가장 큰 문제인지 진단해볼 수 있을까요? 해결법은 찾지 못하더라도, 어느 부분이 가장 문제가 있다고 말할 수는 있어야 합니다.

EXPLAIN ANALYZE
SELECT T1.CUS_ID ,COUNT(*) CNT
FROM   T_ORD_BIG T1 
WHERE  T1.ORD_DT = STR_TO_DATE('20170103','%Y%m%d')
GROUP BY T1.CUS_ID;
-> Table scan on <temporary>  (actual time=5992..5992 rows=9 loops=1)
    -> Aggregate using temporary table  (actual time=5992..5992 rows=9 loops=1)
        -> Filter: (t1.ORD_DT = ('20170103')) (actual time=35.4..5985 rows=18000 loops=1)
            -> Table scan on T1 (actual time=0.0889..5303 rows=6.09e+6 loops=1)


해결법은 기회가 된다면 다음 글에 이어서 적어보도록 하겠습니다. 감사합니다.

 

아래는 지금까지의 내용을 PDF로 정리한 문서입니다.

20240424_StartUPTuning_실행계획.pdf
0.35MB

 

 

StartUP Tuning 오프라인 강의에서는 지금까지 설명한 내용을 아래와 같은 슬라이드로 설명합니다.

 

 

 

[StartUP Tuning]

 

StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문

「StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문」 < 일정 > 5/12(일), 5/19(일), 5/26(일) 오전 9시 ~ 오후 5시 (...

cafe.naver.com

[StartUP SQL]

 

StartUP SQL 소개 및 목차

SQL을 배우기 위한 최적의 시작점 StartUP SQL! 교육 슬라이드 전체를 블로그에 무료 오픈했습니다. (총 409장 슬라이드, 이미지로 게시) 아래 목차를 차례대로 하나씩 따라해보시기 바랍니다. 본인의

sweetquant.tistory.com

 

이번 StartUP Tuning(MySQL을 활용한 SQL 튜닝 입문) 교재에 실릴 Booster Quiz입니다.

교육 앞 부분의 문제인만큼, 인덱스 구조만 이해하면 누구라도 풀수 있는 수준의 문제입니다.
교재에 직접 손으로 그려보면서, "아~ 인덱스가 이렇게 작동하는구나"를 느낄 수 있는 간단한 문제입니다.
("입문" 교육이라고 말씀을 드리긴 하지만, 교육 중반 정도 넘어가면 어려운 문제들이 나옵니다.)

교육은 언제나 진정성 있게 하자란 생각으로, 교재도 공을 들여 준비중입니다.

 

 

 

 


[StartUP Tuning]

  - SQL 입문을 넘어선 MySQL을 활용한 SQL 튜닝 입문 교육
  - 2024년 5월 오프라인 교육 과정 모집중: https://cafe.naver.com/dbian/7717

 

StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문

「StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문」 < 일정 > 5/12(일), 5/19(일), 5/26(일) 오전 9시 ~ 오후 5시 (...

cafe.naver.com

 

[StartUP SQL]

  - 데이터 분석가, 개발자, 기획자를 위한 SQL 입문 교육

  - 교육용 슬라이드 전체 무료 오픈: https://sweetquant.tistory.com/497

 

StartUP SQL 소개 및 목차

SQL을 배우기 위한 최적의 시작점 StartUP SQL! 교육 슬라이드 전체를 블로그에 무료 오픈했습니다. (총 409장 슬라이드, 이미지로 게시) 아래 목차를 차례대로 하나씩 따라해보시기 바랍니다. 본인의

sweetquant.tistory.com

 

 

 

 

오늘은 StartUP Tuning 강의 중 일부인 "언제까지 인덱스를 탈 것만 같아?" 부분을 소개해봅니다.

MySQL로 데이터를 조회할 때 언제까지 인덱스를 사용하는지, 언제나 인덱스가 좋은 것인지에 대한 내용입니다.


SQL의 성능을 위해서는 기본적으로 세 개의 요소가 필요합니다. StartUP Tuning에서는 아래와 같이 세 개의 요소를 정의합니다.

  • INDEX
  • 비효율 SQL 변경(제거)
  • 힌트 사용

이 외에도 SQL 성능을 위해 다양한 요소가 필요하겠지만 기본적으로 가장 신경써야 할 부분은 위의 세 가지입니다.

 

SQL 성능을 위해 인덱스를 잘 구성해야 합니다. 기본적인 인덱스 구성 없이 SQL 성능을 끌어 올리는 것은 불가능합니다.

그러나 인덱스가 잘 구성되어 있어도 SQL을 잘 작성하지 않는다면 아무 필요가 없습니다.

(StartUP Tuning 강의에서는 인덱스를 하루에 걸쳐 설명하지만, 항상 SQL의 중요성을 강조합니다.)

SQL이 실행되면 MySQL의 옵티마이져는 상황에 따라서 인덱스로 처리할지 테이블 FULL SCAN으로 처리할지 선택하게 됩니다. 이는 인덱스를 사용하는 것이 항상 성능에 유리하지는 않다는 뜻이기도 합니다.

 

아래와 같은 SQL의 조건을 변경해가면서 실행하면, 어느 지점부터 인덱스가 아닌 FULL SCAN을 선택하는지 간단히 살펴볼 수 있습니다. T_ORD_BIG에는 약 6백만건의 데이터가 존재하며 ORD_YMD 컬럼에 싱글 컬럼 인덱스가 존재합니다. SELECT 절에 일부러 인덱스에 없는 PAY_DT 컬럼을 사용해 인덱스를 사용한 후 테이블 접근이 발생하도록 유도했습니다. 

SELECT  MAX(T1.PAY_DT) MAX_PAY_DT, COUNT(*) CNT
FROM    T_ORD_BIG T1 
WHERE   T1.ORD_YMD >= '20170104'
AND     T1.ORD_YMD <  '20170110';

 

조회 조건을 변경해가면서 테스트를 해보면 아래와 같은 결과를 얻을 수 있습니다. 조회 건수가 450,000 건 정도가 되자 인덱스가 아닌 Table Scan(TABLE FULL SCAN)을 선택했습니다. (이는 인덱스로 데이터를 탐색 후 테이블 접근이 발생하는 것이 전제된 경우입니다. 만약에 테이블 접근 없이 인덱스만 사용한다면 다른 결과가 나올 것입니다.) 실행시간 역시 342,000건 까지는 1.75초 정도였으나 450,000건인 Table Scan부터는 7.05 초로 매우 느려진 것을 알 수 있습니다.

 

MySQL의 옵티마이져는 통계를 참고해 450,000건 정도부터는 인덱스보다는 Table Scan이 더 빠르다 판단한 것입니다. 

항상 옵티마이져가 최선의 선택을 하는 것은 아닙니다. 최선의 선택을 위해 주어진 환경에서 최대한 노력하지만, 최선의 선택이 아닐 수도 있습니다. 실제로 현재 환경에서 450,000건 정도는 Table Scan보다 인덱스를 활용한 처리가 더 빠릅니다. 위 결과를 시각화 해보면 다음과 같습니다. Table Scan(FULL SCAN)에서 Buffers(IO) 수치는 꺽이지만 실행 시간은 오히려 7초대까지 올라간 것을 알 수 있습니다.

 

여기서 주의할 점이 있습니다. 450,000이 Table Scan을 선택하는 일반화된 숫자가 절대 아니라는 점입니다. 이러한 숫자는 서버와 디스크 성능, 서버 설정, 테이블의 크기(로우x컬럼), 인덱스 구성, 통계, SQL문 등에 의해 다른 결과가 나올 수 있습니다. 제 개인 PC에 설치된 MySQL에서 이와 같은 수치가 나온 것이므로 각자 환경에서 큰 테이블을 기준으로 테스트 해보시기 바랍니다.

 

추가로 하나의 테스트를 더 해 봅니다. 조회 건수를 변경해가면서 INDEX 또는 NO_INDEX 힌트를 적용해 성능 비교를 하는 것입니다. 아래와 같은 결과를 얻을 수 있습니다.

 

450,000건을 처리할 때 인덱스를 사용한 경우에는 3.28초 정도의 시간이 걸린 것을 알 수 있습니다. 해당 건수의 FULL SCAN 시간은 6.64초 정도가 나왔습니다. (이전 테스트에서 7.05초 정도였습니다. 약간 시간이 줄어들었으나 크게 의미는 없습니다.)

위 내용을 시각화 해보면 다음과 같습니다.

 

Table Scan(FULL SCAN)은 몇 건의 데이터를 조회하든 거의 일정한 시간과 거의 일정한 IO를 유지합니다. 반면에 인덱스를 이용한 데이터 접근은 어느 순간(450,000 건을 넘어서는 순간)부터 IO와 실행시간이 급등하기 시작합니다.

이처럼 조회할 데이터가 많아질 수록 인덱스보다 Table Scan(FULL SCAN)이 SQL 성능을 위해 더 좋은 선택일 수 있습니다. (한번 더 강조하면, 이와 같은 수치는 테스트 환경에 따라 상이합니다.)

 

조회할 데이터가 많으면 Table Scan이 더 좋다! 그러나, SQL 튜닝에 많은 도움을 주시는 변동구 이사님께서 이런 말씀을 하셨습니다. "지금도 빠르고 앞으로도 빠를 것인가?"

현재 테스트한 T_ORD_BIG에는 6백만건 정도의 데이터가 있습니다.

데이터가 지금의 열 배가 된다면, 여전히 Table Scan(FULL SCAN)이 인덱스를 활용한 검색보다 빠를 수 있을지는 생각을 해볼 필요가 있습니다.

 

StartUP Tuning(MySQL을 활용한 SQL 튜닝 입문 교육)에서는 지금까지의 내용을 다음과 같은 슬라이드로 소개합니다.

 

 

 


오늘 준비한 내용은 여기까지입니다. 정리해보면 다음과 같습니다.

  • 옵티마이져는 데이터 처리량에 따라 인데스와 Table Scan 중에 선택을 한다.
  • 옵티마이져의 선택이 완벽하지 않을 수도 있다.
  • 실제로 처리할 건수가 많아질 수록 인덱스보다는 Table Scan이 더 효과적이다.
  • 그러나 "지금도 빠르고 앞으로도 빠를것인가?" 에 대해 고민해보자.

감사합니다.


[StartUP Tuning]

  - SQL 입문을 넘어선 MySQL을 활용한 SQL 튜닝 입문 교육
  - 2024년 5월 오프라인 교육 과정을 모집중입니다.

  - https://cafe.naver.com/dbian/7717

 

StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문

「StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문」 < 일정 > 5/12(일), 5/19(일), 5/26(일) 오전 9시 ~ 오후 5시 (...

cafe.naver.com

 

[StartUP SQL]

  - 데이터 분석가, 개발자, 기획자를 위한 SQL 입문 교육

  - 교육용 슬라이드 전체 무료 오픈: https://sweetquant.tistory.com/497

 

StartUP SQL 소개 및 목차

SQL을 배우기 위한 최적의 시작점 StartUP SQL! 교육 슬라이드 전체를 블로그에 무료 오픈했습니다. (총 409장 슬라이드, 이미지로 게시) 아래 목차를 차례대로 하나씩 따라해보시기 바랍니다. 본인의

sweetquant.tistory.com

 

 

분석대상을 로우별로 다르게 지정할 수 있는 윈도윙절입니다.

그리고 준비한 자료는 여기까지입니다. 수고하셨습니다.^^

 

 


이전 슬라이드: https://sweetquant.tistory.com/549

다음 슬라이드: 마지막입니다. 

StartUP SQL 교육 슬라이드 전체 목차로 이동

https://sweetquant.tistory.com/497

 

StartUP SQL 소개 및 목차

데이터를 강력하게 다루는 SQL! SQL을 배우기 위한 최적의 시작점 StartUP SQL! 교육 슬라이드를 이미지로 블로그에 무료 오픈했습니다. (총 409장의 슬라이드입니다.) 아래 목차를 차례대로 하나씩 따

sweetquant.tistory.com

 

SQL 입문을 넘어선 MySQL을 활용한 SQL 튜닝 교육 [StartUP Tuning] 오프라인 교육 과정을 모집중입니다.

https://cafe.naver.com/dbian/7717

 

StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문

「StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문」 < 일정 > 5/12(일), 5/19(일), 5/26(일) 오전 9시 ~ 오후 5시 (...

cafe.naver.com

 

 

'SQL > StartUP SQL(교육슬라이드)' 카테고리의 다른 글

20-2. LAG와 LEAD  (0) 2024.04.11
19-3. 순위 분석함수  (0) 2024.04.11
19-1~19-2. 분석함수 이해하기  (0) 2024.04.11
18. 날짜 테이블  (0) 2024.04.11
17. PIVOT  (0) 2024.04.11
16-3. ROLLUP  (0) 2024.04.11
16-1~16.2. UNION ALL  (0) 2024.04.11
15-4. WITH  (0) 2024.04.04

다른 로우의 데이터를 현재 로우로 가져올 수 있는 LAG와 LEAD를 살펴보겠습니다.

 

 


이전 교육 슬라이드: https://sweetquant.tistory.com/548
다음 교육 슬라이드: https://sweetquant.tistory.com/550
StartUP SQL 교육 슬라이드 전체 목차: https://sweetquant.tistory.com/497

 

StartUP SQL 소개 및 목차

데이터를 강력하게 다루는 SQL! SQL을 배우기 위한 최적의 시작점 StartUP SQL! 교육 슬라이드를 이미지로 블로그에 무료 오픈했습니다. (총 409장의 슬라이드입니다.) 아래 목차를 차례대로 하나씩 따

sweetquant.tistory.com

 

SQL 입문을 넘어선 MySQL을 활용한 SQL 튜닝 교육 [StartUP Tuning]
2024년 5월 오프라인 교육 과정을 모집중입니다.
https://cafe.naver.com/dbian/7717

 

StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문

「StartUP Tuning - MySQL/MariaDB를 활용한 SQL 튜닝 입문」 < 일정 > 5/12(일), 5/19(일), 5/26(일) 오전 9시 ~ 오후 5시 (...

cafe.naver.com

 

'SQL > StartUP SQL(교육슬라이드)' 카테고리의 다른 글

20-3. WINDOWING  (0) 2024.04.11
19-3. 순위 분석함수  (0) 2024.04.11
19-1~19-2. 분석함수 이해하기  (0) 2024.04.11
18. 날짜 테이블  (0) 2024.04.11
17. PIVOT  (0) 2024.04.11
16-3. ROLLUP  (0) 2024.04.11
16-1~16.2. UNION ALL  (0) 2024.04.11
15-4. WITH  (0) 2024.04.04

+ Recent posts