Files
document-haness/docs/n+1liner/tech-log-studio/jpa-feed-query-performance/decision/decision-keyset-for-feed-pagination.md
T

2.8 KiB

id, kind, slug, title, topic, project, status, studio, decisionStatus
id kind slug title topic project status studio decisionStatus
1dbce381-f0dc-4d49-ad68-bd31d205677e PROJECT_DECISION keyset-for-feed-pagination Feed Pagination은 Keyset을 사용한다 JPA 피드 조회 성능 Liner N + 1문제 게시 전 https://hyeonworks.com/studio/documents/1dbce381-f0dc-4d49-ad68-bd31d205677e/edit PROPOSED

Feed Pagination은 Keyset을 사용한다

피드 목록의 페이징은 OFFSET이 아니라 이전 페이지의 마지막 정렬키를 커서로 넘기는 방식을 쓴다. 정렬키와 같은 컬럼·같은 방향의 인덱스를 함께 둔다.

근거

  • Keyset Pagination 설계 기준 이 결정을 규칙으로 편 기준이다.
  • Visibility OR이 Keyset Index를 깨뜨린 문제 깊이별 비용과 인덱스 전제를 확인한 기록이다.
  • Highlight 없는 FeedItem을 허용할 것인가 커서 설계가 기다리는 판단이다.

결정문

피드 목록은 (정렬 시각, 식별자)를 커서로 사용해 그 지점 이후만 조회한다. 정렬키 전용 인덱스를 같은 컬럼과 방향으로 둔다.

전체 페이지 수를 요구하지 않는 화면에서는 전체 건수 count를 발행하지 않는다.

판단 이유

OFFSET은 정렬 순서에서 앞의 행을 만든 뒤 버린다. 깊은 페이지에서는 결과 20행을 만들려고 2,000행을 읽었다. 무한 스크롤에서는 뒤로 갈수록 이 비용이 계속 늘어난다.

커서 방식은 읽는 행이 페이지 깊이와 무관하게 페이지 크기로 유지됐다. 정렬키 인덱스가 있을 때 커서 이후만 인덱스에서 읽었고 읽은 블록도 최소였다.

인덱스를 제거하면 커서 방식도 전량을 스캔했다. 문법이 아니라 인덱스가 비용을 줄인다. 기존 인덱스는 선두 컬럼이 달라 이 쿼리에 쓰이지 않았고 정렬키 전용 인덱스가 따로 필요했다.

정렬 시각이 같은 행을 안정적으로 넘기려면 식별자까지 커서에 담아야 한다. 시각만 쓰면 경계에서 행이 빠지거나 중복된다.

영향

  • 임의 페이지로 점프할 수 없다. 앞뒤로 이어서 넘기는 탐색만 가능하다.
  • 전체 페이지 수를 화면에 표시할 수 없다. 필요하면 count를 별도로 다뤄야 한다.
  • 정렬 기준마다 인덱스가 필요하다. 정렬 기준이 늘면 인덱스 수와 쓰기 비용이 함께 는다.
  • 정렬키가 null일 수 있으면 정렬 위치와 커서 표현을 먼저 정의해야 한다. 이 판단이 아직 열려 있다.
  • 필터가 붙으면 인덱스 전제가 깨질 수 있다. 가시성 조건을 얹었을 때 정렬키 인덱스가 쓰이지 않고 정렬이 다시 생겼다. 필터를 포함한 설계가 따로 필요하다.
  • 커서를 클라이언트에 노출하므로 인코딩과 위변조 처리를 정해야 한다.