▤ 목차
최근 3일 이내에 가입한 유저 조회하기
데이터 조회
SELECT * FROM users
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
인덱스를 추가하기전
인덱스 추가 후
CREATE INDEX idx_created_at ON users (created_at);
created_at 에 인덱스를 추가함으로써 검색 타입이 ALL 에서 range 로 바뀌고 소요시간이 약 0.35 초 에서 0.056 초로 감소
Sales 부서이면서 최근 3일 이내에 가입한 유저 조회하기
데이터 생성
DROP TABLE IF EXISTS users;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
department VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
100만건 데이터 생성 후 데이터 조회해서 성능 측정
SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY)
실행계획 확인
EXPLAIN SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
#세부내용
EXPLAIN ANALYZE SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
-> Filter: ((users.department = 'Sales') and (users.created_at >= <cache>((now() - interval 3 day)))) (cost=93877 rows=33224) (actual time=3.34..243 rows=115 loops=1)
-> Table scan on users (cost=93877 rows=996810) (actual time=0.148..191 rows=1e+6 loops=1)
성능개선 할 수 있는 방법들
1. created_at 컬럼을 기준으로 인덱스 추가
2. department 컬럼을 기준으로 인덱스 추가
3. department 와 created_at 두 컬럼에 인덱스 추가
4. 멀티 컬럼 인덱스 = (created_at, department) ? (department, created_at) ?
< created_at 컬럼을 기준으로 인덱스 추가 >
CREATE INDEX idx_created_at ON users (created_at);
#성능평가
SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
# 실행 계획
EXPLAIN SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
# 실행 계획 세부 내용
EXPLAIN ANALYZE SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
0.24초 에서 0.033 초로 소요시간 단축
type = range , 모든 테이블을 검색하지 않고 idx_created_at 인덱스 레인지 스캔을 함 데이터 접근 개수(rows)도 줄어들었다.
< department 컬럼을 기준으로 인덱스 추가 >
ALTER TABLE users DROP INDEX idx_created_at; # 기존 created_at 인덱스 삭제
CREATE INDEX idx_department ON users (department);
# 성능 측정
SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
# 실행 계획
EXPLAIN SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
# 실행 계획 세부 내용
EXPLAIN ANALYZE SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
약 0.13초 소요 created_at 컬럼을 기준으로 인덱스 추가 한 경우가 소요시간이 훨씬 짧음
ref 타입, = 비고유 인덱스로 조회를 했다 rows = 191,314 는 인덱스를 하기전 보다 좋아 졌지만 created_at 컬럼을 기준으로 인덱스 추가 한 경우보다 많은 데이터에 접근
<department 와 created_at 두 컬럼에 인덱스 추가>
# CREATE INDEX idx_department ON users (department); # 위에서 이미 추가함
CREATE INDEX idx_created_at ON users (created_at); # created_at 인덱스 추가
# 성능 측정
SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
# 실행 계획
EXPLAIN SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
# 실행 계획 세부 내용
EXPLAIN ANALYZE SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
소요 시간은 idx_created_at 과 비슷
idx_created_at 과 똑같이 range 타입으로 일정 범위만 검색
-> Filter: (users.department = 'Sales') (cost=498 rows=212) (actual time=0.0929..11.6 rows=114 loops=1)
-> Index range scan on users using idx_created_at over ('2024-12-27 16:39:14' <= created_at), with index condition: (users.created_at >= <cache>((now() - interval 3 day))) (cost=498 rows=1106) (actual time=0.062..11.3 rows=1106 loops=1)
디테일을 확인해 보면 idx_created_at 만 사용
결론적으로 idx_department 을 사용하지 않았다는 것은 department 컬럼에 한 인덱스가 필요가 없고 판단하여 idx_department는 의미 성능평가에서도 비슷하므로 created_at 컬럼에만 인덱스를 하는 것이 가장 효율적인 최적화 방법으로 볼수 있다.
[이것만은 꼭 기억해두자!]
데이터 액세스(rows)를 크게 줄일 수 있는 컬럼은 중복 정도가 낮은 컬럼이다.
따라서 중복 정도가 낮은 컬럼을 골라서 인덱스를 생성해라.
< 멀티 컬럼 인덱스 >
공통 : 성능테스트
SELECT * FROM users
WHERE department = 'Sales'
AND created_at >= DATE_SUB(NOW(), INTERVAL 3 DAY);
순서 (created_at, department)
ALTER TABLE users DROP INDEX idx_created_at;
ALTER TABLE users DROP INDEX idx_department;
CREATE INDEX idx_created_at_department ON users (created_at, department);
성능 테스트 결과 : 소요시간 약 0.0035 초
순서 (department, created_at)
ALTER TABLE users DROP INDEX idx_created_at_department;
CREATE INDEX idx_department_created_at ON users (department, created_at);
성능 테스트 결과 : 소요시간 약 0.0033초
멀티 컬럼 인덱스를 사용했지만 created_at 만 인덱스를 설정했을 때의 성능과 크게 차이가 나지 않는다.
’단일 컬럼에 설정하는 일반 인덱스’를 설정했을 때와 ‘멀티 컬럼 인덱스를 설정했을 때’의 성능 차이가 별로 나지 않는다면 ?
▶ 멀티 컬럼 인덱스를 사용하지 말고 일반 인덱스를 활용하자.
비교한 인덱스 방식의 성능 테스트 비교 표
인덱스 방식 | 성능 테스트 (소요시간 (s)) | rows |
인덱스 없음 | 0.24 | 115 |
created_at | 0.0033 | 114 |
department | 0.14 | 114 |
created_at 와 department | 0.0032 | 114 |
멀티 (created_at, department) | 0.0035 | 109 |
멀티 (department, created_at) | 0.0033 | 109 |
참고 강의
'DataBase > MySQL' 카테고리의 다른 글
[ MySQL 최적화 ] 인덱스를 걸었는데도 인덱스가 작동하지 않는 경우 (0) | 2024.12.30 |
---|---|
[ MySQL 최적화 ] 한 번에 너무 많은 데이터를 조회하는 SQL문 튜닝하기 (0) | 2024.12.30 |
[ MySQL 최적화] 실행 계획(EXPLAIN)을 활용해 성능 저하 요인 찾아내기 (0) | 2024.12.28 |
[ MySQL 최적화 ] Index (1) | 2024.12.26 |
MySQL- 가상의 테이블 View (0) | 2023.08.26 |