【ITニュース解説】REST Pagination techniques
2025年10月05日に「Dev.to」が公開したITニュース「REST Pagination techniques」について初心者にもわかりやすく解説しています。
ITニュース概要
データ表示を分割する「ページネーション」には、単純なOffset方式だけでなくCursor方式など複数手法がある。Offset方式は実装が容易だが、大量データでは処理が遅くなる欠点がある。Cursor方式は大量データでも効率的で、最新のAPIで採用される。データの規模や用途に応じて最適な手法を選ぶことが重要だ。
ITニュース解説
ウェブアプリケーションやシステム開発において、非常に多くのデータをユーザーに表示する必要がある場面は少なくない。例えば、何万件もの商品が並ぶオンラインストアや、日々更新される膨大な記事が投稿されるニュースサイトなどを想像してみてほしい。これらすべてのデータを一度に表示しようとすれば、ウェブページの読み込みに時間がかかったり、サーバーに大きな負担がかかったりして、結果的にユーザーは快適にサービスを利用できなくなる。このような問題を解決するために、データをいくつかのまとまりに分割し、必要な部分だけを順番に表示する技術が「ページネーション」である。これは、まるで本のページをめくるように、データを少しずつ見せることで、ユーザー体験を向上させ、システムの負荷を適切に管理するための重要な技術だ。
これまでの一般的な考え方として、ページネーションは「何番目のデータから何件取得するか」を指定すれば実現できる、という比較的シンプルなものだと思われがちだった。このアプローチは「オフセットページネーション」と呼ばれ、データベースからデータを取得する際に、OFFSETというキーワードで開始位置を指定し、LIMITというキーワードで取得する件数を指定する。たとえば、SELECT * FROM data ORDER BY id OFFSET 1000 LIMIT 10;というデータベースへの命令文は、「ID順に並べたデータの中から、最初の1000件を飛ばして、その次の10件を取得する」という意味になる。この方法の大きな利点は、実装が非常に簡単であることと、ユーザーが「〇ページ目に直接移動したい」といった要望に応えやすい点だ。そのため、扱うデータ量がそこまで多くないシステムでは、このオフセットページネーションは非常に有効な手段となる。
しかし、オフセットページネーションにはいくつかの欠点が存在する。最も深刻なのは、データセットが大規模になった場合にパフォーマンスが著しく低下するという問題だ。もしOFFSET 1000000 LIMIT 10のように、非常に大きなオフセット値を指定すると、データベースは目的の10件のデータを取得するために、まずその100万件分のデータを読み込み、それらを破棄するという無駄な処理を行う必要がある。この「データを読み飛ばす」という処理は、読み飛ばす件数が増えるほど時間がかかり、システムの応答速度を大幅に低下させる原因となる。また、ユーザーがページをめくる間に、データベースのデータが追加されたり削除されたりすると、表示されるデータが予期せず重複したり、一部が抜け落ちたりするといった「データの一貫性の問題」が発生する可能性もある。
「ページページネーション」は、このオフセットページネーションを、ユーザーにとってより分かりやすい形で提供するための方法である。ユーザーは「100ページ目を、1ページあたり10件表示する」といった形で操作するが、システム内部ではこれをOFFSET (ページ番号 - 1) * 1ページあたりの件数 LIMIT 1ページあたりの件数という形でオフセット値に変換して処理している。この方法もユーザーインターフェースの使いやすさという点では優れているが、内部的にはオフセットページネーションと同じ仕組みを使っているため、大規模データセットにおける性能問題やデータの一貫性の問題は依然として残る。
これらのオフセットページネーションの課題を解決するために開発されたのが、「カーソルページネーション」である。カーソルページネーションは、OFFSETのような数値による相対的な位置ではなく、データの特定の項目(例えば、データのIDや、データが作成された日時など、一意で順番に並べられる値)を「カーソル」として使用し、そのカーソルよりも新しいデータや古いデータを取得するという全く異なるアプローチをとる。例えば、SELECT * FROM pagination_dataset WHERE id > cursor_id ORDER BY id LIMIT 10;というデータベースへの命令文は、「特定のcursor_idよりも大きいIDを持つデータの中から、ID順に並べて最初の10件を取得する」という意味になる。この方法の最大の利点は、データベースが不要なデータをスキャンして破棄する必要がないため、非常に効率的であることだ。特にデータ量が膨大で、常に新しいデータが追加されていくようなシステム(例えば、SNSのタイムラインやログデータなど)において、優れた処理能力を発揮する。現代のGitHub、Twitter、Facebookといった大手サービスが提供するAPIも、このカーソルページネーションを採用していることが多い。
一方で、カーソルページネーションには、「特定のページに直接ジャンプする」といった機能を実装するのが難しいという側面がある。これは、カーソルが「次に取得すべきデータの基準点」を示すものであり、絶対的なページ番号とは考え方が異なるためだ。また、カーソルとしてデータベースの内部的なID値などを直接使用すると、その情報が外部に公開されてしまうリスクがあるため、アプリケーション側でカーソル情報を加工・変換(エンコード)して提供するなどの工夫が必要になることもある。このエンコード処理はわずかながらシステムの処理に影響を与える可能性もある。
「キーセットページネーション」は、カーソルページネーションと非常によく似た概念を持つ。基本的な考え方は、データの特定の値(キー)を基準に次のデータや前のデータを取得する、という点でカーソルページネーションと同じである。キーセットページネーションでは、アプリケーションがカーソルとなるオブジェクトを生成してクライアントに返すことで、データベースの内部情報を直接外部に公開するのを防ぐことができる。
これらの異なるページネーション技術が存在するため、開発者がどの方法を選択すべきか判断に迷うことも少なくないだろう。記事の筆者は、実際にオフセットページネーションとカーソルページネーションの性能を比較する実験を行い、その結果としてカーソルページネーションの効率性の高さが確認されたことを示唆している。
結論として、ページネーションの選択は、開発するシステムの規模や用途によって最適なものが異なる。もし扱うデータ量が少なく、ユーザーが特定のページに直接移動する機能が重要視される場合は、実装が簡単なオフセットページネーションやページページネーションが適している。しかし、大量のデータを扱う大規模なシステムや、外部に公開するAPI、無限スクロールのような機能が必要な場合には、カーソルページネーションやキーセットページネーションが圧倒的に高いパフォーマンスを発揮する。特に、公開APIを構築する際には、そのスケーラビリティと効率性の高さからカーソルページネーションを選択することが強く推奨される。ページネーションは一見すると単純な機能に見えるかもしれないが、システムが大規模になった際に適切な選択をしていれば、将来的に発生するかもしれない重大なパフォーマンス問題を未然に防ぎ、システムの安定稼働に大きく貢献することになるだろう。