24. 유일하지 않은 정렬 키의 키셋 페이지네이션: 경계 행 누락

난이도 상 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] 키셋(seek) 페이지네이션의 정렬 키가 유일하지 않은 경우
// ----------------------------------------------------------------------------
// 시나리오:
//   길드원 목록을 레벨 내림차순으로 페이지 단위로 조회한다. OFFSET 대신 키셋(seek)
//   페이지네이션을 써서, 다음 페이지는 "직전 페이지 마지막 행의 레벨보다 낮은" 행부터 가져온다.
//   길드에는 같은 레벨의 길드원이 여럿 있을 수 있다.
//
// 요구사항:
//   - 전체 길드원이 페이지를 넘겨가며 정확히 한 번씩 조회되어야 한다(누락/중복 금지).
//
// 과제:
//   MemberPageRepo.GetNextPage 의 (A) 쿼리 조건과 (B) 커서 갱신을 검토하라.
//   같은 레벨의 길드원이 페이지 경계에 걸치는 상황을 따라가며 결과와 수정 방향을 설명하라.
// ============================================================================

using System.Collections.Generic;

public readonly struct MemberRow
{
    public readonly long MemberId;
    public readonly int Level;
    public MemberRow(long id, int lvl) { MemberId = id; Level = lvl; }
}

public sealed class Page
{
    public IReadOnlyList<MemberRow> Rows { get; }
    public int? NextCursorLevel { get; }     // null 이면 마지막 페이지
    public Page(IReadOnlyList<MemberRow> rows, int? next) { Rows = rows; NextCursorLevel = next; }
}

public sealed class MemberPageRepo
{
    private readonly IDb _db;
    public MemberPageRepo(IDb db) { _db = db; }

    public Page GetNextPage(long guildId, int? afterLevel, int pageSize)
    {
        string sql = afterLevel is null
            ? "SELECT member_id, level FROM guild_members " +
              "WHERE guild_id=@g ORDER BY level DESC LIMIT @n"
            : "SELECT member_id, level FROM guild_members " +
              "WHERE guild_id=@g AND level < @lvl " +           // (A)
              "ORDER BY level DESC LIMIT @n";

        var rows = _db.Query(sql, guildId, afterLevel ?? 0, pageSize);

        int? next = rows.Count == pageSize ? rows[rows.Count - 1].Level : (int?)null;  // (B)
        return new Page(rows, next);
    }
}

public interface IDb { IReadOnlyList<MemberRow> Query(string sql, long guildId, int level, int limit); }
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.