이번에 새롭게 바뀐 소설 조회의 정렬 기준에 따라 모든 정렬 쿼리를 수정해야 했다. 그 중 가장 첫번째로 인기순 정렬을 수정하게 되었는데, 그 과정에서 생긴 일들을 1편과 2편에 걸쳐서 설명해보려고 한다.

기존에는 인기순의 정렬 기준이 아래와 같았다.

  1. 3일간 집계된 조회수
  2. 쿼리 대상 테이블(novel_period_stats)의 PK

하지만 이번에 변경된 인기순의 정렬 기준은 다음과 같다.

  1. 3일간 집계된 조회수
  2. 현재까지 누적된 총 조회수
  3. 쿼리 대상 테이블의 PK

원래는 tie-breaker 역할을 하는 PK 컬럼을 제외하면 사실 상 정렬 기준은 3일간 집계된 조회수 하나밖에 없었지만, 이제는 소설의 총 조회수가 2순위로 추가되어 조금 더 정확하게 인기순으로 정렬할 수 있게 되었다.

그런데 누적 총 조회수는 novel 테이블에만 존재하고, novel_period_stats 테이블에는 존재하지 않는다. 그래서 바뀐 정렬 로직을 구현하려면 아래와 같은 쿼리가 필요하다.

select 
	n.*, 
	nps.id, nps.view_count
from 
	novel_period_stats nps
join 
	novel n on nps.novel_id = n.id
where
	nps.start_date = ? and nps.end_date = ?
	and (
		nps.view_count < ?
		or nps.view_count = ? and n.total_view_count < ?
		or nps.view_count = ? and n.total_view_count = ? and nps.id < ?
	)
order by
	nps.view_count desc,
	n.total_view_count desc,
	nps.id desc
limit 50;

나는 이 쿼리를 그대로 쓰기에는 조금 문제가 있을 것 같다고 판단하였다. 왜냐하면 where, order by 절에서 novel_period_stats 의 컬럼만 사용하는 것이 아니라 novel의 컬럼까지 같이 사용하기 때문이다.

이것이 문제가 되는 이유는 바로 인덱스 때문이다. 보통 저런 쿼리를 매번 실시간으로 실행하려면 복합 인덱스가 있어야 많은 데이터 양에서도 어느정도의 속도를 보장할 수 있는데, where, order by 에서 단일 테이블의 컬럼이 아니라 다른 테이블의 컬럼까지 사용하게 되면 그 모든 컬럼을 하나의 복합 인덱스로 만들수가 없어 속도가 저하될 수 있다.

원래라면 여기서 실행계획 정도만 추가로 확인한 후 문제를 해결하려고 했겠지만, 이번에는 실제로 얼마나 차이가 나는지 조금 더 확인해보고 싶어졌다. 그래서 간단히 아래 3가지 쿼리에 따라 속도차이가 얼마나 나는지 확인해보았다.

테스트 조건은 아래와 같았다.