SlideShare une entreprise Scribd logo
1  sur  41
MYSQL - 실행계획
김천규
1
SQL
절차(How)가 아닌 대상(What)을 기술하는 언어
HOW를 의식하는 것이 SQL 튜닝의 첫 걸음
=> DB의 구성요소, 역할, 흐름을 알아야 한다.
2
DBMS 아키텍처
3
MYSQL 구조
4
Optimizer(옵티마이저)
5
규칙기반 옵티마이저
6
비용기반 옵티마이저
7
옵티마이저 입장에서는 전부 다른 쿼리 (파서)
SELECT * FROM 급여;
SELECt * FROM 급여;
SELECT * fROM 급여;
8
인덱스(Index)
9
인덱스를 타면 이렇게 되요
10
Index는 일반적으로 B+tree 구조
11
Table Scan
12
JOIN
13
JOIN
14
속도로는 R(A) JOIN R(B) != R(A) JOIN R(B)
15
실행계획 JOIN
1. Nested Loop
2. Sort Merge Join
3. Hash Join
16
Nested Loop
17
Sort Merge Join
18
Hash Join
19
SQL 튜닝을 한다는 거는
• 옵티마이저가 최적의 비용으로 수행하게 잘 유도 하는 것
• 테이블 스캔 횟수는 최소화
20
실무적인 SQL 튜닝
1. SQL문 실행결과 & 현황 파악 결과 및 소요 시간 확인
조인/서브쿼리 구조
동등/범위 조건
2. 가시적 & 비가시적 가시적 테이블의 데이터 건수
SELECT절 컬럼 분석
조건절 컬럼 분석
그루핑/정렬 컬럼
비가시적 실행계획
인덱스 현황
데이터 변경 추이
*업무적 특성*
3. 튜닝 방향 판단 & 개선/적용
21
실행 계획 판단 기준
일반적으로 그렇다는 의미이며
특이케이스가 있을 수 있음
22
기본키를 변형하는 나쁜 SQL – ASIS (4.2.1)
SELECT *
FROM 사원
WHERE SUBSTRING(사원번호,1,4) = 1100
AND LENGTH(사원번호) = 5;
* 결과
+----------+------------+-------------+-------------+------+------------+
| 사원번호 | 생년월일 | 이름 | 성 | 성별 | 입사일자 |
+----------+------------+-------------+-------------+------+------------+
| 11000 | 1960-09-12 | Alain | Bonifati | M | 1988-08-20 |
| 11001 | 1956-04-16 | Baziley | Buchter | F | 1987-02-23 |
| 11002 | 1952-02-26 | Bluma | Ulupinar | M | 1996-12-23 |
| 11003 | 1960-11-13 | Mariangiola | Gulla | M | 1987-05-24 |
| 11004 | 1954-08-05 | JoAnna | Decleir | F | 1992-01-19 |
| 11005 | 1958-03-12 | Byong | Douceur | F | 1986-07-27 |
| 11006 | 1962-12-26 | Christoper | Butterworth | F | 1989-08-02 |
| 11007 | 1962-03-16 | Olivera | Maccarone | M | 1991-04-11 |
| 11008 | 1962-07-11 | Gennady | Menhoudj | M | 1988-09-18 |
| 11009 | 1954-08-30 | Alper | Axelband | F | 1986-09-09 |
+----------+------------+-------------+-------------+------+------------+
10 rows in set (0.21 sec)
====================================================================================
23
사원번호가 1100으로 시작하면서 사원번호가 5자리인 사원 정보
기본키를 변형하는 나쁜 SQL – 실행계획 (4.2.1)
EXPLAIN
SELECT *
FROM 사원
WHERE SUBSTRING(사원번호,1,4) = 1100
AND LENGTH(사원번호) = 5;
* 결과
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+------
----+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered
| Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+------
----+-------------+
| 1 | SIMPLE | 사원 | NULL | ALL | NULL | NULL | NULL | NULL | 299157 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+------
----+-------------+
1 row in set, 1 warning (0.00 sec)
24
기본키를 변형하는 나쁜 SQL – TOBE (4.2.1)
SELECT *
FROM 사원
WHERE 사원번호 BETWEEN 11000 AND 11009;
* 결과
+----------+------------+-------------+-------------+------+------------+
| 사원번호 | 생년월일 | 이름 | 성 | 성별 | 입사일자 |
+----------+------------+-------------+-------------+------+------------+
| 11000 | 1960-09-12 | Alain | Bonifati | M | 1988-08-20 |
| 11001 | 1956-04-16 | Baziley | Buchter | F | 1987-02-23 |
| 11002 | 1952-02-26 | Bluma | Ulupinar | M | 1996-12-23 |
| 11003 | 1960-11-13 | Mariangiola | Gulla | M | 1987-05-24 |
| 11004 | 1954-08-05 | JoAnna | Decleir | F | 1992-01-19 |
| 11005 | 1958-03-12 | Byong | Douceur | F | 1986-07-27 |
| 11006 | 1962-12-26 | Christoper | Butterworth | F | 1989-08-02 |
| 11007 | 1962-03-16 | Olivera | Maccarone | M | 1991-04-11 |
| 11008 | 1962-07-11 | Gennady | Menhoudj | M | 1988-09-18 |
| 11009 | 1954-08-30 | Alper | Axelband | F | 1986-09-09 |
+----------+------------+-------------+-------------+------+------------+
10 rows in set (0.00 sec)
25
형변환으로 인덱스를 활용하지 못하는 나쁜 SQL – ASIS (4.2.3)
* SQL
SELECT COUNT(1)
FROM 급여
WHERE 사용여부 = 1;
* 결과
+----------+
| COUNT(1) |
+----------+
| 42842 |
+----------+
1 row in set (0.15 sec)
26
유효한 급여의 전체 개수 조회
형변환으로 인덱스를 활용하지 못하는 나쁜 SQL – ASIS (4.2.3)
desc 급여;
* 결과
+----------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+-------+
| 사원번호 | int | NO | PRI | NULL | |
| 연봉 | int | NO | | NULL | |
| 시작일자 | date | NO | PRI | NULL | |
| 종료일자 | date | NO | | NULL | |
| 사용여부 | char(1) | YES | MUL | | |
+----------+---------+------+-----+---------+-------+
5 rows in set (0.01 sec)
27
형변환으로 인덱스를 활용하지 못하는 나쁜 SQL – TOBE (4.2.3)
====================================================================================
* SQL
SELECT COUNT(1)
FROM 급여
WHERE 사용여부 = '1';
* 결과
+----------+
| COUNT(1) |
+----------+
| 42842 |
+----------+
1 row in set (0.01 sec)
28
열을 결합하여 사용하는 나쁜 SQL – ASIS, 실행계획 (4.2.4)
* SQL
EXPLAIN
SELECT *
FROM 사원
WHERE CONCAT(성별,' ',성) = 'M Radwan';
* 결과
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+------
----+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered
| Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+------
----+-------------+
| 1 | SIMPLE | 사원 | NULL | ALL | NULL | NULL | NULL | NULL | 299157 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+------
----+-------------+
1 row in set, 1 warning (0.00 sec)
29
열을 결합하여 사용하는 나쁜 SQL – TOBE, 실행계획 (4.2.4)
* SQL
EXPLAIN
SELECT *
FROM 사원
WHERE 성별 = 'M'
AND 성 = 'Radwan';
* 결과
+----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+----
---+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+----
---+
| 1 | SIMPLE | 사원 | NULL | ref | I_성별_성 | I_성별_성 | 51 | const,const | 102 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+----
---+
1 row in set, 1 warning (0.00 sec)
30
인덱스 고려 없이 열을 사용하는 SQL – ASIS (4.2.7)
* SQL
SELECT 성, 성별, COUNT(1) as 카운트
FROM 사원
GROUP BY 성, 성별;
* 결과
+------------------+------+--------+
| 성 | 성별 | 카운트 |
+------------------+------+--------+
| Aamodt | M | 120 |
| Acton | M | 108 |
| Adachi | M | 140 |
... 중략 ...
| Zwicker | F | 65 |
| Zyda | F | 72 |
| Zykh | F | 61 |
+------------------+------+--------+
3274 rows in set (0.43 sec)
31
인덱스 고려 없이 열을 사용하는 SQL – 인덱스 조회 (4.2.7)
* SQL
show index from 사원;
* 결과
+-------+------------+------------+--------------+-------------+-----------+-------------
+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality |
Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+------------+--------------+-------------+-----------+-------------
+----------+--------+------+------------+---------+---------------+---------+------------+
| 사원 | 0 | PRIMARY | 1 | 사원번호 | A | 299157 | NULL | NULL | | BTREE | | | YES | NULL |
| 사원 | 1 | I_입사일자 | 1 | 입사일자 | A | 4612 | NULL | NULL | | BTREE | | | YES | NULL |
| 사원 | 1 | I_성별_성 | 1 | 성별 | A | 1 | NULL | NULL | | BTREE | | | YES | NULL |
| 사원 | 1 | I_성별_성 | 2 | 성 | A | 3257 | NULL | NULL | | BTREE | | | YES | NULL |
+-------+------------+------------+--------------+-------------+-----------+-------------
+----------+--------+------+------------+---------+---------------+---------+------------+
4 rows in set (0.00 sec)
32
인덱스 고려 없이 열을 사용하는 SQL – TOBE (4.2.7)
* SQL
SELECT 성, 성별, COUNT(1) as 카운트
FROM 사원
GROUP BY 성별, 성;
* 결과
+------------------+------+--------+
| 성 | 성별 | 카운트 |
+------------------+------+--------+
| Aamodt | M | 120 |
| Acton | M | 108 |
| Adachi | M | 140 |
... 중략 ...
| Zwicker | F | 65 |
| Zyda | F | 72 |
| Zykh | F | 61 |
+------------------+------+--------+
3274 rows in set (0.04 sec)
33
습관적으로 중복을 제거하는 나쁜 SQL – ASIS, 실행계획 (4.2.5)
EXPLAIN
SELECT DISTINCT 사원.사원번호, 이름, 성, 부서번호
FROM 사원
JOIN 부서관리자
ON (사원.사원번호 = 부서관리자. 사원번호);
* 결과
+----+-------------+------------+------------+--------+---------------+------------+---------+----------------------------
+------+----------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+--------+---------------+------------+---------+----------------------------
+------+----------+------------------------------+
| 1 | SIMPLE | 부서관리자 | NULL | index | PRIMARY | I_부서번호 | 12 | NULL | 24 | 100.00 | Using index; Using temporary |
| 1 | SIMPLE | 사원 | NULL | eq_ref | PRIMARY | PRIMARY | 4 | tuning.부서관리자.사원번호 | 1 | 100.00 | NULL |
+----+-------------+------------+------------+--------+---------------+------------+---------+----------------------------
+------+----------+------------------------------+
2 rows in set, 1 warning (0.00 sec)
34
습관적으로 중복을 제거하는 나쁜 SQL – TOBE, 실행계획 (4.2.5)
EXPLAIN
SELECT 사원.사원번호, 이름, 성, 부서번호
FROM 사원
JOIN 부서관리자
ON (사원.사원번호 = 부서관리자. 사원번호);
* 결과
+----+-------------+------------+------------+--------+---------------+------------+---------+----------------------------
+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+--------+---------------+------------+---------+----------------------------
+------+----------+-------------+
| 1 | SIMPLE | 부서관리자 | NULL | index | PRIMARY | I_부서번호 | 12 | NULL | 24 | 100.00 | Using index |
| 1 | SIMPLE | 사원 | NULL | eq_ref | PRIMARY | PRIMARY | 4 | tuning.부서관리자.사원번호 | 1 | 100.00 | NULL |
+----+-------------+------------+------------+--------+---------------+------------+---------+----------------------------
+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
35
다수의 쿼리를 UNION 연산자로 합치는 나쁜 SQL – ASIS, 실행계획
(4.2.6)
EXPLAIN
SELECT 'M' AS 성별, 사원번호
FROM 사원
WHERE 성별 = 'M'
AND 성 ='Baba'
UNION
SELECT 'F', 사원번호
FROM 사원
WHERE 성별 = 'F'
AND 성 = 'Baba';
* 결과
+------+--------------+------------+------------+------+---------------+-----------+---------+-------------+------+----------+-----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+------+--------------+------------+------------+------+---------------+-----------+---------+-------------+------+----------+-----------------+
| 1 | PRIMARY | 사원 | NULL | ref | I_성별_성 | I_성별_성 | 51 | const,const | 135 | 100.00 | Using index |
| 2 | UNION | 사원 | NULL | ref | I_성별_성 | I_성별_성 | 51 | const,const | 91 | 100.00 | Using index |
| NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+------+--------------+------------+------------+------+---------------+-----------+---------+-------------+------+----------+-----------------+
3 rows in set, 1 warning (0.00 sec)
36
다수의 쿼리를 UNION 연산자로 합치는 나쁜 SQL – TOBE, 실행계획
(4.2.6)
EXPLAIN
SELECT 'M' as 성별, 사원번호
FROM 사원
WHERE 성별 = 'M'
AND 성 ='Baba'
UNION ALL
SELECT 'F' as 성별, 사원번호
FROM 사원
WHERE 성별 = 'F'
AND 성 ='Baba';
* 결과
+----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+
| 1 | PRIMARY | 사원 | NULL | ref | I_성별_성 | I_성별_성 | 51 | const,const | 135 | 100.00 | Using index |
| 2 | UNION | 사원 | NULL | ref | I_성별_성 | I_성별_성 | 51 | const,const | 91 | 100.00 | Using index |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
37
불필요한 조인을 수행하는 나쁜 SQL – ASIS, 실행계획 (4.3.3)
* SQL
EXPLAIN
SELECT COUNT(DISTINCT 사원.사원번호) as 데이터건수
FROM 사원,
( SELECT 사원번호
FROM 사원출입기록 기록
WHERE 출입문 = 'A'
) 기록
WHERE 사원.사원번호 = 기록.사원번호;
* 결과
+----+-------------+-------+------------+--------+---------------+----------+---------+----------------------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+----------+---------+----------------------+--------+----------+-------------+
| 1 | SIMPLE | 기록 | NULL | ref | I_출입문 | I_출입문 | 4 | const | 329467 | 100.00 | Using index |
| 1 | SIMPLE | 사원 | NULL | eq_ref | PRIMARY | PRIMARY | 4 | tuning.기록.사원번호 | 1 | 100.00 | Using index |
+----+-------------+-------+------------+--------+---------------+----------+---------+----------------------+--------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
38
불필요한 조인을 수행하는 나쁜 SQL – TOBE, 실행계획 (4.3.3)
• * SQL
• EXPLAIN
• SELECT COUNT(1) as 데이터건수
• FROM 사원
• WHERE EXISTS (SELECT 1
• FROM 사원출입기록 기록
• WHERE 출입문 = 'A'
• AND 기록.사원번호 = 사원.사원번호);
• * 결과
• +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+----------------------+--------+-----
-----+--------------------------+
• | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
• +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+----------------------+--------+-----
-----+--------------------------+
• | 1 | SIMPLE | 사원 | NULL | index | PRIMARY | I_입사일자 | 3 | NULL | 299157 | 100.00 | Using where; Using index |
• | 1 | SIMPLE | <subquery2> | NULL | eq_ref | <auto_distinct_key> | <auto_distinct_key> | 4 | tuning.사원.사원번호 | 1 | 100.00 | NULL |
• | 2 | MATERIALIZED | 기록 | NULL | ref | I_출입문 | I_출입문 | 4 | const | 329467 | 100.00 | Using index |
• +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+----------------------+--------+-----
-----+--------------------------+
• 3 rows in set, 2 warnings (0.00 sec)
39
Reference
• 업무에 바로 쓰는 SQL 튜닝
• SQL 레벨업
• Effective SQL
• Real Mysql
40
감사합니다.
41

Contenu connexe

Similaire à MySQL 실행계획

SQL Profile을 이용한 SQL Plan 변경_Wh oracle
SQL Profile을 이용한 SQL Plan 변경_Wh oracleSQL Profile을 이용한 SQL Plan 변경_Wh oracle
SQL Profile을 이용한 SQL Plan 변경_Wh oracle엑셈
 
#6.SQL초보에서 Schema Objects까지_구로IT학원/오라클교육/자바교육/국비지원/재직자환급교육/내일배움카드/사업주위탁
#6.SQL초보에서 Schema Objects까지_구로IT학원/오라클교육/자바교육/국비지원/재직자환급교육/내일배움카드/사업주위탁#6.SQL초보에서 Schema Objects까지_구로IT학원/오라클교육/자바교육/국비지원/재직자환급교육/내일배움카드/사업주위탁
#6.SQL초보에서 Schema Objects까지_구로IT학원/오라클교육/자바교육/국비지원/재직자환급교육/내일배움카드/사업주위탁탑크리에듀(구로디지털단지역3번출구 2분거리)
 
효율적인Sql작성방법 2주차
효율적인Sql작성방법 2주차효율적인Sql작성방법 2주차
효율적인Sql작성방법 2주차희동 강
 
(재직자환급교육/사업주위탁/IT실무교육/구로IT학원/오라클교육/SQL기초강좌/IT강좌)#10.SQL초보에서 Schema Objects까지
(재직자환급교육/사업주위탁/IT실무교육/구로IT학원/오라클교육/SQL기초강좌/IT강좌)#10.SQL초보에서 Schema Objects까지(재직자환급교육/사업주위탁/IT실무교육/구로IT학원/오라클교육/SQL기초강좌/IT강좌)#10.SQL초보에서 Schema Objects까지
(재직자환급교육/사업주위탁/IT실무교육/구로IT학원/오라클교육/SQL기초강좌/IT강좌)#10.SQL초보에서 Schema Objects까지탑크리에듀(구로디지털단지역3번출구 2분거리)
 
[Pgday.Seoul 2021] 1. 예제로 살펴보는 포스트그레스큐엘의 독특한 SQL
[Pgday.Seoul 2021] 1. 예제로 살펴보는 포스트그레스큐엘의 독특한 SQL[Pgday.Seoul 2021] 1. 예제로 살펴보는 포스트그레스큐엘의 독특한 SQL
[Pgday.Seoul 2021] 1. 예제로 살펴보는 포스트그레스큐엘의 독특한 SQLPgDay.Seoul
 
Amazon aurora 2
Amazon aurora 2Amazon aurora 2
Amazon aurora 2EXEM
 
#12.SQL초보에서 schema Objects까지(구로IT학원/IT실무교육학원/국비지원IT교육학원/오라클교육/자바교육/닷넷교육학원추천)
#12.SQL초보에서 schema Objects까지(구로IT학원/IT실무교육학원/국비지원IT교육학원/오라클교육/자바교육/닷넷교육학원추천)#12.SQL초보에서 schema Objects까지(구로IT학원/IT실무교육학원/국비지원IT교육학원/오라클교육/자바교육/닷넷교육학원추천)
#12.SQL초보에서 schema Objects까지(구로IT학원/IT실무교육학원/국비지원IT교육학원/오라클교육/자바교육/닷넷교육학원추천)탑크리에듀(구로디지털단지역3번출구 2분거리)
 
Database 튜닝 교육 110124
Database 튜닝 교육 110124Database 튜닝 교육 110124
Database 튜닝 교육 110124한 경만
 
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3Seok-joon Yun
 

Similaire à MySQL 실행계획 (18)

집합함수(2)
집합함수(2)집합함수(2)
집합함수(2)
 
SQL Profile을 이용한 SQL Plan 변경_Wh oracle
SQL Profile을 이용한 SQL Plan 변경_Wh oracleSQL Profile을 이용한 SQL Plan 변경_Wh oracle
SQL Profile을 이용한 SQL Plan 변경_Wh oracle
 
2.4 optimizer mode를 변경하는 힌트(choose)
2.4 optimizer mode를 변경하는 힌트(choose)2.4 optimizer mode를 변경하는 힌트(choose)
2.4 optimizer mode를 변경하는 힌트(choose)
 
3.4 실행계획 SQL 연산 (Hash Anti-Join)
3.4 실행계획 SQL 연산 (Hash Anti-Join)3.4 실행계획 SQL 연산 (Hash Anti-Join)
3.4 실행계획 SQL 연산 (Hash Anti-Join)
 
#6.SQL초보에서 Schema Objects까지_구로IT학원/오라클교육/자바교육/국비지원/재직자환급교육/내일배움카드/사업주위탁
#6.SQL초보에서 Schema Objects까지_구로IT학원/오라클교육/자바교육/국비지원/재직자환급교육/내일배움카드/사업주위탁#6.SQL초보에서 Schema Objects까지_구로IT학원/오라클교육/자바교육/국비지원/재직자환급교육/내일배움카드/사업주위탁
#6.SQL초보에서 Schema Objects까지_구로IT학원/오라클교육/자바교육/국비지원/재직자환급교육/내일배움카드/사업주위탁
 
Sql기초강좌2_SET AUTOTRACE_SQL교육
Sql기초강좌2_SET AUTOTRACE_SQL교육Sql기초강좌2_SET AUTOTRACE_SQL교육
Sql기초강좌2_SET AUTOTRACE_SQL교육
 
5.2 비트맵 인덱스
5.2 비트맵 인덱스5.2 비트맵 인덱스
5.2 비트맵 인덱스
 
효율적인Sql작성방법 2주차
효율적인Sql작성방법 2주차효율적인Sql작성방법 2주차
효율적인Sql작성방법 2주차
 
2.1 optimizer mode를 변경하는 힌트(rule)
2.1 optimizer mode를 변경하는 힌트(rule)2.1 optimizer mode를 변경하는 힌트(rule)
2.1 optimizer mode를 변경하는 힌트(rule)
 
3.2 실행계획 sql 연산 (concatenation)
3.2 실행계획 sql 연산 (concatenation)3.2 실행계획 sql 연산 (concatenation)
3.2 실행계획 sql 연산 (concatenation)
 
Sql 조건연산자를 이용한 조건검색(1)
Sql 조건연산자를 이용한 조건검색(1)Sql 조건연산자를 이용한 조건검색(1)
Sql 조건연산자를 이용한 조건검색(1)
 
(재직자환급교육/사업주위탁/IT실무교육/구로IT학원/오라클교육/SQL기초강좌/IT강좌)#10.SQL초보에서 Schema Objects까지
(재직자환급교육/사업주위탁/IT실무교육/구로IT학원/오라클교육/SQL기초강좌/IT강좌)#10.SQL초보에서 Schema Objects까지(재직자환급교육/사업주위탁/IT실무교육/구로IT학원/오라클교육/SQL기초강좌/IT강좌)#10.SQL초보에서 Schema Objects까지
(재직자환급교육/사업주위탁/IT실무교육/구로IT학원/오라클교육/SQL기초강좌/IT강좌)#10.SQL초보에서 Schema Objects까지
 
[Pgday.Seoul 2021] 1. 예제로 살펴보는 포스트그레스큐엘의 독특한 SQL
[Pgday.Seoul 2021] 1. 예제로 살펴보는 포스트그레스큐엘의 독특한 SQL[Pgday.Seoul 2021] 1. 예제로 살펴보는 포스트그레스큐엘의 독특한 SQL
[Pgday.Seoul 2021] 1. 예제로 살펴보는 포스트그레스큐엘의 독특한 SQL
 
Amazon aurora 2
Amazon aurora 2Amazon aurora 2
Amazon aurora 2
 
#12.SQL초보에서 schema Objects까지(구로IT학원/IT실무교육학원/국비지원IT교육학원/오라클교육/자바교육/닷넷교육학원추천)
#12.SQL초보에서 schema Objects까지(구로IT학원/IT실무교육학원/국비지원IT교육학원/오라클교육/자바교육/닷넷교육학원추천)#12.SQL초보에서 schema Objects까지(구로IT학원/IT실무교육학원/국비지원IT교육학원/오라클교육/자바교육/닷넷교육학원추천)
#12.SQL초보에서 schema Objects까지(구로IT학원/IT실무교육학원/국비지원IT교육학원/오라클교육/자바교육/닷넷교육학원추천)
 
Database 튜닝 교육 110124
Database 튜닝 교육 110124Database 튜닝 교육 110124
Database 튜닝 교육 110124
 
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
[2015-06-26] Oracle 성능 최적화 및 품질 고도화 3
 
1.11 실행계획 해석 predicate
1.11 실행계획 해석 predicate1.11 실행계획 해석 predicate
1.11 실행계획 해석 predicate
 

Plus de Wonjun Hwang

스토리북(Storybook, Kitworks Team Study 우아라 발표)
스토리북(Storybook, Kitworks Team Study 우아라 발표)스토리북(Storybook, Kitworks Team Study 우아라 발표)
스토리북(Storybook, Kitworks Team Study 우아라 발표)Wonjun Hwang
 
mysql8 전환기 (Kitworks Team Study 김천규 발표자료)
mysql8 전환기 (Kitworks Team Study 김천규 발표자료)mysql8 전환기 (Kitworks Team Study 김천규 발표자료)
mysql8 전환기 (Kitworks Team Study 김천규 발표자료)Wonjun Hwang
 
Open AI SORA (키트웍스 팀스터디 발표자료 박준기 240315)
Open AI SORA  (키트웍스 팀스터디 발표자료 박준기 240315)Open AI SORA  (키트웍스 팀스터디 발표자료 박준기 240315)
Open AI SORA (키트웍스 팀스터디 발표자료 박준기 240315)Wonjun Hwang
 
Nest JS (Kitworks Team Study 이본훈 발표 240315)
Nest JS (Kitworks Team Study 이본훈 발표 240315)Nest JS (Kitworks Team Study 이본훈 발표 240315)
Nest JS (Kitworks Team Study 이본훈 발표 240315)Wonjun Hwang
 
JS Event Loop (Kitworks Team Study 김동현 발표)
JS Event Loop (Kitworks Team Study 김동현 발표)JS Event Loop (Kitworks Team Study 김동현 발표)
JS Event Loop (Kitworks Team Study 김동현 발표)Wonjun Hwang
 
Java Optional (Kitworks Team Study 김성호 발표)
Java Optional (Kitworks Team Study 김성호 발표)Java Optional (Kitworks Team Study 김성호 발표)
Java Optional (Kitworks Team Study 김성호 발표)Wonjun Hwang
 
XSS(Cross site scripting) - Kitworks Team Study
XSS(Cross site scripting) - Kitworks Team StudyXSS(Cross site scripting) - Kitworks Team Study
XSS(Cross site scripting) - Kitworks Team StudyWonjun Hwang
 
Flutter & Firebase (2) Kitworks Team Study
Flutter & Firebase (2) Kitworks Team StudyFlutter & Firebase (2) Kitworks Team Study
Flutter & Firebase (2) Kitworks Team StudyWonjun Hwang
 
얕은복사,깊은복사
얕은복사,깊은복사얕은복사,깊은복사
얕은복사,깊은복사Wonjun Hwang
 
Go언어로 디스코드 봇 만들기
Go언어로 디스코드 봇 만들기Go언어로 디스코드 봇 만들기
Go언어로 디스코드 봇 만들기Wonjun Hwang
 
완전 유용한 CSS 모음
완전 유용한 CSS 모음완전 유용한 CSS 모음
완전 유용한 CSS 모음Wonjun Hwang
 
2024 개발 트렌드
2024 개발 트렌드2024 개발 트렌드
2024 개발 트렌드Wonjun Hwang
 
디바운싱과 쓰로틀링
디바운싱과 쓰로틀링디바운싱과 쓰로틀링
디바운싱과 쓰로틀링Wonjun Hwang
 
스마트한 팀 협업
스마트한 팀 협업스마트한 팀 협업
스마트한 팀 협업Wonjun Hwang
 
구름톤 8기 후기
구름톤 8기 후기구름톤 8기 후기
구름톤 8기 후기Wonjun Hwang
 
2024년 키워드로 알아보는 트렌드
2024년 키워드로 알아보는 트렌드2024년 키워드로 알아보는 트렌드
2024년 키워드로 알아보는 트렌드Wonjun Hwang
 

Plus de Wonjun Hwang (20)

스토리북(Storybook, Kitworks Team Study 우아라 발표)
스토리북(Storybook, Kitworks Team Study 우아라 발표)스토리북(Storybook, Kitworks Team Study 우아라 발표)
스토리북(Storybook, Kitworks Team Study 우아라 발표)
 
mysql8 전환기 (Kitworks Team Study 김천규 발표자료)
mysql8 전환기 (Kitworks Team Study 김천규 발표자료)mysql8 전환기 (Kitworks Team Study 김천규 발표자료)
mysql8 전환기 (Kitworks Team Study 김천규 발표자료)
 
Open AI SORA (키트웍스 팀스터디 발표자료 박준기 240315)
Open AI SORA  (키트웍스 팀스터디 발표자료 박준기 240315)Open AI SORA  (키트웍스 팀스터디 발표자료 박준기 240315)
Open AI SORA (키트웍스 팀스터디 발표자료 박준기 240315)
 
Nest JS (Kitworks Team Study 이본훈 발표 240315)
Nest JS (Kitworks Team Study 이본훈 발표 240315)Nest JS (Kitworks Team Study 이본훈 발표 240315)
Nest JS (Kitworks Team Study 이본훈 발표 240315)
 
JS Event Loop (Kitworks Team Study 김동현 발표)
JS Event Loop (Kitworks Team Study 김동현 발표)JS Event Loop (Kitworks Team Study 김동현 발표)
JS Event Loop (Kitworks Team Study 김동현 발표)
 
Java Optional (Kitworks Team Study 김성호 발표)
Java Optional (Kitworks Team Study 김성호 발표)Java Optional (Kitworks Team Study 김성호 발표)
Java Optional (Kitworks Team Study 김성호 발표)
 
XSS(Cross site scripting) - Kitworks Team Study
XSS(Cross site scripting) - Kitworks Team StudyXSS(Cross site scripting) - Kitworks Team Study
XSS(Cross site scripting) - Kitworks Team Study
 
Flutter & Firebase (2) Kitworks Team Study
Flutter & Firebase (2) Kitworks Team StudyFlutter & Firebase (2) Kitworks Team Study
Flutter & Firebase (2) Kitworks Team Study
 
PWA
PWAPWA
PWA
 
얕은복사,깊은복사
얕은복사,깊은복사얕은복사,깊은복사
얕은복사,깊은복사
 
Go언어로 디스코드 봇 만들기
Go언어로 디스코드 봇 만들기Go언어로 디스코드 봇 만들기
Go언어로 디스코드 봇 만들기
 
완전 유용한 CSS 모음
완전 유용한 CSS 모음완전 유용한 CSS 모음
완전 유용한 CSS 모음
 
2024 개발 트렌드
2024 개발 트렌드2024 개발 트렌드
2024 개발 트렌드
 
디바운싱과 쓰로틀링
디바운싱과 쓰로틀링디바운싱과 쓰로틀링
디바운싱과 쓰로틀링
 
Passkey
PasskeyPasskey
Passkey
 
스마트한 팀 협업
스마트한 팀 협업스마트한 팀 협업
스마트한 팀 협업
 
AI News '23.12
AI News '23.12AI News '23.12
AI News '23.12
 
Google Analytics
Google AnalyticsGoogle Analytics
Google Analytics
 
구름톤 8기 후기
구름톤 8기 후기구름톤 8기 후기
구름톤 8기 후기
 
2024년 키워드로 알아보는 트렌드
2024년 키워드로 알아보는 트렌드2024년 키워드로 알아보는 트렌드
2024년 키워드로 알아보는 트렌드
 

MySQL 실행계획

  • 2. SQL 절차(How)가 아닌 대상(What)을 기술하는 언어 HOW를 의식하는 것이 SQL 튜닝의 첫 걸음 => DB의 구성요소, 역할, 흐름을 알아야 한다. 2
  • 8. 옵티마이저 입장에서는 전부 다른 쿼리 (파서) SELECT * FROM 급여; SELECt * FROM 급여; SELECT * fROM 급여; 8
  • 15. 속도로는 R(A) JOIN R(B) != R(A) JOIN R(B) 15
  • 16. 실행계획 JOIN 1. Nested Loop 2. Sort Merge Join 3. Hash Join 16
  • 20. SQL 튜닝을 한다는 거는 • 옵티마이저가 최적의 비용으로 수행하게 잘 유도 하는 것 • 테이블 스캔 횟수는 최소화 20
  • 21. 실무적인 SQL 튜닝 1. SQL문 실행결과 & 현황 파악 결과 및 소요 시간 확인 조인/서브쿼리 구조 동등/범위 조건 2. 가시적 & 비가시적 가시적 테이블의 데이터 건수 SELECT절 컬럼 분석 조건절 컬럼 분석 그루핑/정렬 컬럼 비가시적 실행계획 인덱스 현황 데이터 변경 추이 *업무적 특성* 3. 튜닝 방향 판단 & 개선/적용 21
  • 22. 실행 계획 판단 기준 일반적으로 그렇다는 의미이며 특이케이스가 있을 수 있음 22
  • 23. 기본키를 변형하는 나쁜 SQL – ASIS (4.2.1) SELECT * FROM 사원 WHERE SUBSTRING(사원번호,1,4) = 1100 AND LENGTH(사원번호) = 5; * 결과 +----------+------------+-------------+-------------+------+------------+ | 사원번호 | 생년월일 | 이름 | 성 | 성별 | 입사일자 | +----------+------------+-------------+-------------+------+------------+ | 11000 | 1960-09-12 | Alain | Bonifati | M | 1988-08-20 | | 11001 | 1956-04-16 | Baziley | Buchter | F | 1987-02-23 | | 11002 | 1952-02-26 | Bluma | Ulupinar | M | 1996-12-23 | | 11003 | 1960-11-13 | Mariangiola | Gulla | M | 1987-05-24 | | 11004 | 1954-08-05 | JoAnna | Decleir | F | 1992-01-19 | | 11005 | 1958-03-12 | Byong | Douceur | F | 1986-07-27 | | 11006 | 1962-12-26 | Christoper | Butterworth | F | 1989-08-02 | | 11007 | 1962-03-16 | Olivera | Maccarone | M | 1991-04-11 | | 11008 | 1962-07-11 | Gennady | Menhoudj | M | 1988-09-18 | | 11009 | 1954-08-30 | Alper | Axelband | F | 1986-09-09 | +----------+------------+-------------+-------------+------+------------+ 10 rows in set (0.21 sec) ==================================================================================== 23 사원번호가 1100으로 시작하면서 사원번호가 5자리인 사원 정보
  • 24. 기본키를 변형하는 나쁜 SQL – 실행계획 (4.2.1) EXPLAIN SELECT * FROM 사원 WHERE SUBSTRING(사원번호,1,4) = 1100 AND LENGTH(사원번호) = 5; * 결과 +----+-------------+-------+------------+------+---------------+------+---------+------+--------+------ ----+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+------ ----+-------------+ | 1 | SIMPLE | 사원 | NULL | ALL | NULL | NULL | NULL | NULL | 299157 | 100.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+------ ----+-------------+ 1 row in set, 1 warning (0.00 sec) 24
  • 25. 기본키를 변형하는 나쁜 SQL – TOBE (4.2.1) SELECT * FROM 사원 WHERE 사원번호 BETWEEN 11000 AND 11009; * 결과 +----------+------------+-------------+-------------+------+------------+ | 사원번호 | 생년월일 | 이름 | 성 | 성별 | 입사일자 | +----------+------------+-------------+-------------+------+------------+ | 11000 | 1960-09-12 | Alain | Bonifati | M | 1988-08-20 | | 11001 | 1956-04-16 | Baziley | Buchter | F | 1987-02-23 | | 11002 | 1952-02-26 | Bluma | Ulupinar | M | 1996-12-23 | | 11003 | 1960-11-13 | Mariangiola | Gulla | M | 1987-05-24 | | 11004 | 1954-08-05 | JoAnna | Decleir | F | 1992-01-19 | | 11005 | 1958-03-12 | Byong | Douceur | F | 1986-07-27 | | 11006 | 1962-12-26 | Christoper | Butterworth | F | 1989-08-02 | | 11007 | 1962-03-16 | Olivera | Maccarone | M | 1991-04-11 | | 11008 | 1962-07-11 | Gennady | Menhoudj | M | 1988-09-18 | | 11009 | 1954-08-30 | Alper | Axelband | F | 1986-09-09 | +----------+------------+-------------+-------------+------+------------+ 10 rows in set (0.00 sec) 25
  • 26. 형변환으로 인덱스를 활용하지 못하는 나쁜 SQL – ASIS (4.2.3) * SQL SELECT COUNT(1) FROM 급여 WHERE 사용여부 = 1; * 결과 +----------+ | COUNT(1) | +----------+ | 42842 | +----------+ 1 row in set (0.15 sec) 26 유효한 급여의 전체 개수 조회
  • 27. 형변환으로 인덱스를 활용하지 못하는 나쁜 SQL – ASIS (4.2.3) desc 급여; * 결과 +----------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+---------+------+-----+---------+-------+ | 사원번호 | int | NO | PRI | NULL | | | 연봉 | int | NO | | NULL | | | 시작일자 | date | NO | PRI | NULL | | | 종료일자 | date | NO | | NULL | | | 사용여부 | char(1) | YES | MUL | | | +----------+---------+------+-----+---------+-------+ 5 rows in set (0.01 sec) 27
  • 28. 형변환으로 인덱스를 활용하지 못하는 나쁜 SQL – TOBE (4.2.3) ==================================================================================== * SQL SELECT COUNT(1) FROM 급여 WHERE 사용여부 = '1'; * 결과 +----------+ | COUNT(1) | +----------+ | 42842 | +----------+ 1 row in set (0.01 sec) 28
  • 29. 열을 결합하여 사용하는 나쁜 SQL – ASIS, 실행계획 (4.2.4) * SQL EXPLAIN SELECT * FROM 사원 WHERE CONCAT(성별,' ',성) = 'M Radwan'; * 결과 +----+-------------+-------+------------+------+---------------+------+---------+------+--------+------ ----+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+------ ----+-------------+ | 1 | SIMPLE | 사원 | NULL | ALL | NULL | NULL | NULL | NULL | 299157 | 100.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+------ ----+-------------+ 1 row in set, 1 warning (0.00 sec) 29
  • 30. 열을 결합하여 사용하는 나쁜 SQL – TOBE, 실행계획 (4.2.4) * SQL EXPLAIN SELECT * FROM 사원 WHERE 성별 = 'M' AND 성 = 'Radwan'; * 결과 +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+---- ---+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+---- ---+ | 1 | SIMPLE | 사원 | NULL | ref | I_성별_성 | I_성별_성 | 51 | const,const | 102 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+---- ---+ 1 row in set, 1 warning (0.00 sec) 30
  • 31. 인덱스 고려 없이 열을 사용하는 SQL – ASIS (4.2.7) * SQL SELECT 성, 성별, COUNT(1) as 카운트 FROM 사원 GROUP BY 성, 성별; * 결과 +------------------+------+--------+ | 성 | 성별 | 카운트 | +------------------+------+--------+ | Aamodt | M | 120 | | Acton | M | 108 | | Adachi | M | 140 | ... 중략 ... | Zwicker | F | 65 | | Zyda | F | 72 | | Zykh | F | 61 | +------------------+------+--------+ 3274 rows in set (0.43 sec) 31
  • 32. 인덱스 고려 없이 열을 사용하는 SQL – 인덱스 조회 (4.2.7) * SQL show index from 사원; * 결과 +-------+------------+------------+--------------+-------------+-----------+------------- +----------+--------+------+------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +-------+------------+------------+--------------+-------------+-----------+------------- +----------+--------+------+------------+---------+---------------+---------+------------+ | 사원 | 0 | PRIMARY | 1 | 사원번호 | A | 299157 | NULL | NULL | | BTREE | | | YES | NULL | | 사원 | 1 | I_입사일자 | 1 | 입사일자 | A | 4612 | NULL | NULL | | BTREE | | | YES | NULL | | 사원 | 1 | I_성별_성 | 1 | 성별 | A | 1 | NULL | NULL | | BTREE | | | YES | NULL | | 사원 | 1 | I_성별_성 | 2 | 성 | A | 3257 | NULL | NULL | | BTREE | | | YES | NULL | +-------+------------+------------+--------------+-------------+-----------+------------- +----------+--------+------+------------+---------+---------------+---------+------------+ 4 rows in set (0.00 sec) 32
  • 33. 인덱스 고려 없이 열을 사용하는 SQL – TOBE (4.2.7) * SQL SELECT 성, 성별, COUNT(1) as 카운트 FROM 사원 GROUP BY 성별, 성; * 결과 +------------------+------+--------+ | 성 | 성별 | 카운트 | +------------------+------+--------+ | Aamodt | M | 120 | | Acton | M | 108 | | Adachi | M | 140 | ... 중략 ... | Zwicker | F | 65 | | Zyda | F | 72 | | Zykh | F | 61 | +------------------+------+--------+ 3274 rows in set (0.04 sec) 33
  • 34. 습관적으로 중복을 제거하는 나쁜 SQL – ASIS, 실행계획 (4.2.5) EXPLAIN SELECT DISTINCT 사원.사원번호, 이름, 성, 부서번호 FROM 사원 JOIN 부서관리자 ON (사원.사원번호 = 부서관리자. 사원번호); * 결과 +----+-------------+------------+------------+--------+---------------+------------+---------+---------------------------- +------+----------+------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+------------+------------+--------+---------------+------------+---------+---------------------------- +------+----------+------------------------------+ | 1 | SIMPLE | 부서관리자 | NULL | index | PRIMARY | I_부서번호 | 12 | NULL | 24 | 100.00 | Using index; Using temporary | | 1 | SIMPLE | 사원 | NULL | eq_ref | PRIMARY | PRIMARY | 4 | tuning.부서관리자.사원번호 | 1 | 100.00 | NULL | +----+-------------+------------+------------+--------+---------------+------------+---------+---------------------------- +------+----------+------------------------------+ 2 rows in set, 1 warning (0.00 sec) 34
  • 35. 습관적으로 중복을 제거하는 나쁜 SQL – TOBE, 실행계획 (4.2.5) EXPLAIN SELECT 사원.사원번호, 이름, 성, 부서번호 FROM 사원 JOIN 부서관리자 ON (사원.사원번호 = 부서관리자. 사원번호); * 결과 +----+-------------+------------+------------+--------+---------------+------------+---------+---------------------------- +------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+------------+------------+--------+---------------+------------+---------+---------------------------- +------+----------+-------------+ | 1 | SIMPLE | 부서관리자 | NULL | index | PRIMARY | I_부서번호 | 12 | NULL | 24 | 100.00 | Using index | | 1 | SIMPLE | 사원 | NULL | eq_ref | PRIMARY | PRIMARY | 4 | tuning.부서관리자.사원번호 | 1 | 100.00 | NULL | +----+-------------+------------+------------+--------+---------------+------------+---------+---------------------------- +------+----------+-------------+ 2 rows in set, 1 warning (0.00 sec) 35
  • 36. 다수의 쿼리를 UNION 연산자로 합치는 나쁜 SQL – ASIS, 실행계획 (4.2.6) EXPLAIN SELECT 'M' AS 성별, 사원번호 FROM 사원 WHERE 성별 = 'M' AND 성 ='Baba' UNION SELECT 'F', 사원번호 FROM 사원 WHERE 성별 = 'F' AND 성 = 'Baba'; * 결과 +------+--------------+------------+------------+------+---------------+-----------+---------+-------------+------+----------+-----------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +------+--------------+------------+------------+------+---------------+-----------+---------+-------------+------+----------+-----------------+ | 1 | PRIMARY | 사원 | NULL | ref | I_성별_성 | I_성별_성 | 51 | const,const | 135 | 100.00 | Using index | | 2 | UNION | 사원 | NULL | ref | I_성별_성 | I_성별_성 | 51 | const,const | 91 | 100.00 | Using index | | NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary | +------+--------------+------------+------------+------+---------------+-----------+---------+-------------+------+----------+-----------------+ 3 rows in set, 1 warning (0.00 sec) 36
  • 37. 다수의 쿼리를 UNION 연산자로 합치는 나쁜 SQL – TOBE, 실행계획 (4.2.6) EXPLAIN SELECT 'M' as 성별, 사원번호 FROM 사원 WHERE 성별 = 'M' AND 성 ='Baba' UNION ALL SELECT 'F' as 성별, 사원번호 FROM 사원 WHERE 성별 = 'F' AND 성 ='Baba'; * 결과 +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+ | 1 | PRIMARY | 사원 | NULL | ref | I_성별_성 | I_성별_성 | 51 | const,const | 135 | 100.00 | Using index | | 2 | UNION | 사원 | NULL | ref | I_성별_성 | I_성별_성 | 51 | const,const | 91 | 100.00 | Using index | +----+-------------+-------+------------+------+---------------+-----------+---------+-------------+------+----------+-------------+ 2 rows in set, 1 warning (0.00 sec) 37
  • 38. 불필요한 조인을 수행하는 나쁜 SQL – ASIS, 실행계획 (4.3.3) * SQL EXPLAIN SELECT COUNT(DISTINCT 사원.사원번호) as 데이터건수 FROM 사원, ( SELECT 사원번호 FROM 사원출입기록 기록 WHERE 출입문 = 'A' ) 기록 WHERE 사원.사원번호 = 기록.사원번호; * 결과 +----+-------------+-------+------------+--------+---------------+----------+---------+----------------------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+--------+---------------+----------+---------+----------------------+--------+----------+-------------+ | 1 | SIMPLE | 기록 | NULL | ref | I_출입문 | I_출입문 | 4 | const | 329467 | 100.00 | Using index | | 1 | SIMPLE | 사원 | NULL | eq_ref | PRIMARY | PRIMARY | 4 | tuning.기록.사원번호 | 1 | 100.00 | Using index | +----+-------------+-------+------------+--------+---------------+----------+---------+----------------------+--------+----------+-------------+ 2 rows in set, 1 warning (0.00 sec) 38
  • 39. 불필요한 조인을 수행하는 나쁜 SQL – TOBE, 실행계획 (4.3.3) • * SQL • EXPLAIN • SELECT COUNT(1) as 데이터건수 • FROM 사원 • WHERE EXISTS (SELECT 1 • FROM 사원출입기록 기록 • WHERE 출입문 = 'A' • AND 기록.사원번호 = 사원.사원번호); • * 결과 • +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+----------------------+--------+----- -----+--------------------------+ • | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | • +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+----------------------+--------+----- -----+--------------------------+ • | 1 | SIMPLE | 사원 | NULL | index | PRIMARY | I_입사일자 | 3 | NULL | 299157 | 100.00 | Using where; Using index | • | 1 | SIMPLE | <subquery2> | NULL | eq_ref | <auto_distinct_key> | <auto_distinct_key> | 4 | tuning.사원.사원번호 | 1 | 100.00 | NULL | • | 2 | MATERIALIZED | 기록 | NULL | ref | I_출입문 | I_출입문 | 4 | const | 329467 | 100.00 | Using index | • +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+----------------------+--------+----- -----+--------------------------+ • 3 rows in set, 2 warnings (0.00 sec) 39
  • 40. Reference • 업무에 바로 쓰는 SQL 튜닝 • SQL 레벨업 • Effective SQL • Real Mysql 40