2 분 소요

RDB에 날리는 페이징 쿼리는 offset, limit을 활용해서 작성하게 되는데, offset이 커질 수록 성능이 떨어진다는 단점이 있다.
offset이 1만이면 1만개까지 조회한 뒤 그 다음부터 limit 값만큼 데이터를 조회하기 때문이다.

모든 페이징 쿼리에 적용할 수 있는 건 아니지만, 특수한 경우에 no offset 방식을 사용해 빠른 속도로 조회가 가능하다.
no offset은 말 그대로 offset을 사용하지 않겠다는 뜻이다. (offset = 0)
물론 기준점이 필요하기 때문에 위 예시에서의 1만번째 데이터의 순번을 알아야한다. 그럼 아래처럼 작성해줄 수 있다.

SELECT *
FROM my_table
WHERE my_id > {1만번째 데이터 id}
LIMIT 100;
  • 기준점을 이미 알고있으니 시간이 많이 세이브된다.

Elasticsearch에서도 no offset과 비슷한 방식인 searchAfter를 제공한다.
그렇다면 searchAfter를 사용하지 않고 offset, limit(ES에서는 from, size 지만)을 제한없이 사용할 수는 있을까?

정답은 사용할 수 없다. from + size > 10000이면 쿼리를 실행할 수가 없다.
그래서 파라미터를 page=51, size=200로 설정하고 페이지 조회 API를 호출한다면, 아래 에러가 발생하게 된다.

Result window is too large, from + size must be less than or equal to: [10000] but was [10200]. 
See the scroll api for a more efficient way to request large data sets. 
This limit can be set by changing the [index.max_result_window] index level setting.
  • 만약 RDB로 날리는 쿼리였다면 offset 10000, limit 200으로 문제없이 동작했을 것이다.

from + size가 1만이 넘는다면 scroll api를 사용하든, index.max_result_window 값(기본값이 1만)을 수정하든,
searchAfter를 사용하든 해서 쿼리를 날리라는 뜻이다. 참고로 searchAfter는 정렬 기준(sort)이 필수다.

1만이 넘지 않는 선에서 허용된다는 뜻이니까 size는 최대 1만까지 가질 수 있다.
그래서 page=51, size=200로 요청받았다면 searchAfter를 적용했을 때 쿼리를 2번 날리게 된다.

1. from=0, size=10000
2. size=200, searchAfter={1번 쿼리 sort 값}
  • 1번 쿼리 응답에서 나오는 sort 값을 searchAfter에 적용해야한다. 이 값이 기준이 된다.
  • 공식 문서에 예시와 함께 친절하게 써있다!

RDB에 쿼리를 날릴 때는 한방 쿼리로 날리면 쉽게 해결되지만, ES는 그렇지 않다.
from + size > 10000이 되는 순간 나 처리 못하겠어!하고 뱉어버리고 에러가 발생해버리니 주의하자.

요것때문에 정말정말 고생 많이했다😭

(추가) scroll api

scroll apistateful 방식이어서 데이터가 많아지면 메모리 사용량이 급격히 증가할 수 있다고 한다.
그에 반해 searchAfter는 stateless 방식이어서 메모리 사용량이 비교적 적다. (쿼리를 끊어서 sort만 취하니까)

쿼리 한방에 특정 페이지까지 도달하려면 scroll api를 통해서 편리하게 처리가 가능할 수 있다.
하지만 요청을 받은 특정 노드의 메모리 사용량이 많아진다는건 처리량이 떨어질 수 있다는 뜻이기도 하다.

We no longer recommend using the scroll API for deep pagination. If you need to preserve the index state while paging through more than 10,000 hits, use the search_after parameter with a point in time (PIT).

Scrolling is not intended for real time user requests, but rather for processing large amounts of data, e.g. in order to reindex the contents of one data stream or index into a new data stream or index with a different configuration.

공식 문서에서도 페이징 처리에는 scroll api 보다는 searchAfter를 권하고 있다.
대용량 데이터 처리를 해야할 때는 scroll api가 적합하다고 한다.

References

카테고리:

업데이트:

댓글남기기