본문 바로가기
SQL 튜닝/인덱스 조정

[SQL 튜닝] 인덱스를 하나만 사용하는 나쁜 SQL 문

by Johnny's 2023. 8. 2.

인덱스를 하나만 사용하는 나쁜 SQL 문

현황 분석

튜닝 전 실행 계획 |

이름이 Matt이거나 입사일자가 1987년 3월 31일사원정보를 조회하는 쿼리

EXPLAIN
SELECT *
	FROM 사원
	WHERE 이름 = 'Matt' OR 입사일자 = '1987-03-31';

- SQL문 결과 : 총 343건의 결과 출력, 102ms 소요 (소요 시간이 매우 짧음)

- 튜닝 여부를 판단할 때 짧은 소요시간만을 기준으로 삼지 않음 더 나은 쿼리로 변경할 수 있음

- 사원 테이블 : 테이블 풀스캔(type항목 : ALL)로 처리

- 스토리지 엔진으로 모든 데이터를 가져온 뒤 MYSQL 엔진에서 2개의 조건절을 활용하여 데이터를 필터링

 

튜닝 수행

- 우선, 조건절에 해당하는 데이터 분포 확인

 

/* 300024 */
SELECT COUNT(1) FROM 사원;	

/* 233 */
SELECT COUNT(1) FROM 사원
WHERE 이름 = 'Matt';

/* 111 */
SELECT COUNT(1) FROM 사원
WHERE 입사일자 = '1987-03-31';

- 소량의 데이터를 가져올때는 보통 테이블 풀스캔보다 인덱스 스캔이 효율적임

SHOW index FROM 사원;

- I_입사일자 인덱스는 확인되지만 이름 열이 포함된 인덱스는 없음

- 이름 열에 대한 인덱스를 생성하여 조건절이 각각의 인덱스를 사용해 데이터에 접근할 수 있도록 튜닝

ALTER TABLE 사원
ADD INDEX I_이름(이름);

 

튜닝 결과

튜닝 후 실행 계획 |

인덱스 생성한 뒤 SQL문 수행 (튜닝 전과 동일)

EXPLAIN
SELECT *
	FROM 사원
	WHERE 이름 = 'Matt' OR 입사일자 = '1987-03-31';

- 102m→ 1.8ms (시간 단축)

- 2개의 조건절 열이 각각 인덱스 스캔으로 수행되고 각 결과는 병합(type항목: index_merge)

- 이름 = 'Matt' 조건절은 I_이름 인덱스 사용, 입사일자 = '1987-03-31' 조건절I_입사일자 인덱스 사용

- Extra 항목 : Using union(I_이름, I_입사일자) 최종 결과 출력

- 만약 WHERE 절 ~ OR 구문에서 한쪽의 조건절이 동등 조건이 아닌 범위 조건(LIKE, BETWEE 구문) 이라면 index_merge로 처리되지 않을 수 있음

- 실행 계획을 한 뒤 UNION이나 UNION ALL 구문 등으로 분리하는 걸 고려해야 함

 

* 참고

- 업무에 바로쓰는 SQL 튜닝(도서) - 5장 악성 SQL 튜닝으로 전문가 되기

댓글