인덱스를 하나만 사용하는 나쁜 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';
- 102ms → 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 튜닝 > 인덱스 조정' 카테고리의 다른 글
[SQL 튜닝] 비효율적인 인덱스를 사용하는 나쁜 SQL 문 (0) | 2023.08.04 |
---|---|
[SQL 튜닝] 큰 규모의 데이터 변경으로 인덱스에 영향을 주는 나쁜 SQL 문 (0) | 2023.08.03 |
[SQL 튜닝] 인덱스 없이 작은 규모의 데이터를 조회하는 나쁜 SQL 문 (0) | 2023.07.30 |
댓글