지난 개선 후
캐시를 사용해 유지보수성, 직관성을 희생하지 않고 DB 접근을 큰 폭으로 줄였다! 👍
하지만 보다시피 랭킹을 조회하는 쿼리는 아직 full-scan으로 발생한다.
게임이 많아질수록 효율이 뚝뚝 감소할 것이다.
full-scan을 개선해보자
AS-IS
SELECT rank() over (ORDER BY score DESC) as ranking, session_id
FROM apple_game
WHERE is_ended
limit 50;
type=ALL, 즉 full-scan이다.
TO-BE
인덱싱을 걸어보자
is_ended
컬럼으로 끝나지 않은 게임을 제외시킬 수 있다.
create index apple_game_is_ended_index on apple_game (is_ended);
index range scan으로 코스트가 조금 줄었다.
풀어서 얘기하면 ‘끝난 게임’에서만 검색하므로 검색량이 줄었다는 것이다!
score로 정렬이 일어나므로, score로 인덱싱한다.
create index apple_game_score_index on apple_game (score desc);
이건 잘못 판단했다.
is_ended
로 먼저 필터링 한 후 score
로 정렬이 일어나므로, score
에만 인덱스를 거는 것은 의미가 없다!
is_ended
로 필터링된 행들을 score
로 정렬하므로, score
및 is_score
를 복합 인덱스로 설정한다.
create index apple_game_is_ended_score_index on apple_game (is_ended, score desc);
놀랍게도 cost가 처음에 비해 약 55%나 줄었다.
실제 시간상 차이는 더 알아봐야겠지만, 기분이 좋다.
눈여겨 볼 점은 가능한 인덱스가 2개지만, 중복되는 인덱싱이 있어 복합 인덱스 하나만 사용했다는 점이다.
랭킹에 대한 인덱싱을 마쳤다.
나중엔 랭킹을 분기나 달 별로 운영해, 더 적은 범위로 줄여서 검색할 수도 있을 것이다.
의문점
range scan 활용
이런것도 가능하지 않을까?
50등의 점수를 저장한다 → 60점이라고 하면
앞으로 순위를 낼 때는 60점 이상끼리만 내면 된다. → 여기서 또 50등의 점수를 저장한다.
커버링 인덱스?
의도하지 않았지만, 쿼리에 쓰이는 session_id, is_ended, score 모두 인덱싱되었다.
이걸 ‘커버링 인덱스’라고 하는건가?