ページネーションとは - API のカーソル方式とオフセット方式の比較

ページネーションは大量データを分割して返す手法。オフセット方式とカーソル方式の違い・パフォーマンス特性・REST/GraphQL での実装パターンを解説

API設計

ページネーションとは

ページネーション (Pagination) は、大量のデータを一度に返すのではなく、複数のページに分割して返す API 設計手法である。1 万件のデータを 1 回で返すと、レスポンスサイズが巨大になり、レイテンシが増大し、クライアントのメモリを圧迫する。

3 つの方式

3 つの方式を以下にまとめる。

方式仕組みメリットデメリット
オフセット?page=3&limit=20シンプル、任意のページにジャンプ大きなオフセットで遅い
カーソル?cursor=abc123&limit=20大量データでも高速任意のページにジャンプ不可
キーセット?after_id=123&limit=20DB インデックスを活用、高速ソート順が固定

オフセットベース

オフセットベースのコード例を示す。

// GET /users?page=3&limit=20
const offset = (page - 1) * limit; // 40
const users = await db.query('SELECT * FROM users ORDER BY id LIMIT $1 OFFSET $2', [limit, offset]);

// レスポンス
{
  "data": [...],
  "pagination": { "page": 3, "limit": 20, "total": 1500, "totalPages": 75 }
}

問題: OFFSET 10000 は DB が 10,000 行をスキップするため遅い。データが追加・削除されるとページがずれる。

カーソルベース (推奨)

カーソルベース (推奨) のコード例を示す。

// GET /users?cursor=eyJpZCI6MTIzfQ&limit=20
const cursor = decodeCursor(cursorParam); // { id: 123 }
const users = await db.query(
  'SELECT * FROM users WHERE id > $1 ORDER BY id LIMIT $2',
  [cursor.id, limit]
);
const nextCursor = encodeCursor({ id: users[users.length - 1].id });

// レスポンス
{
  "data": [...],
  "pagination": { "nextCursor": "eyJpZCI6MTQzfQ", "hasMore": true }
}

WHERE id > 123 はインデックスを使うため、データ量に関わらず高速だ。

DynamoDB のページネーション

DynamoDBLastEvaluatedKey でカーソルベースのページネーションを提供する。

const result = await ddb.send(new QueryCommand({
  TableName: 'Orders',
  KeyConditionExpression: 'userId = :uid',
  ExpressionAttributeValues: { ':uid': userId },
  Limit: 20,
  ExclusiveStartKey: lastKey, // 前回の LastEvaluatedKey
}));

return {
  items: result.Items,
  nextKey: result.LastEvaluatedKey, // 次のページのカーソル
};

GraphQL のページネーション (Relay Cursor Connection)

GraphQL のページネーション (Relay Cursor Connection) の例を示す。

query {
  users(first: 20, after: "cursor123") {
    edges {
      node { id name email }
      cursor
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

実務での選択基準

実務での選択基準を以下にまとめる。

ケース推奨方式
管理画面のテーブル (ページ番号表示)オフセット
無限スクロールカーソル
API (大量データ)カーソル
DynamoDBカーソル (LastEvaluatedKey)

体系的に学ぶなら関連書籍を参照してほしい。

この記事は役に立ちましたか?

関連用語

関連する記事