詳細検索

ページ化の簡単な紹介

アバター
著者: Chen Ziyu

ページ化の簡単な紹介
Englishから翻訳 • 原文を読む

多くのソフトウェアエンジニアにとって、エンティティのリストを取得するエンドポイントはおそらく最も好んで実装するものです。必要なのは、利用可能なすべてのアイテムを取得できるSQL文とその他いくつかの小さなタスクを作成するだけです。すべてが楽しいゲームでしたが、データベース内のエンティティ数がボトルネックとなり、GETリクエストごとに数万件のアイテムが返ってきます。サーバー側のログには赤くハイライトされたエラーメッセージが大量に現れ始めます。以前はアプリケーションに満足していたユーザーも、パフォーマンスの低下に不満を漏らし始めます。プロダクトマネージャーはもう限界に達し、そのフラストレーションをあなたにぶつけています。えっ?!これらすべてを防ぎたいと言っているのですか?ページネーションこそ必要なものです!それはエンドポイントのパフォーマンスを劇的に向上させ、サーバーの過負荷を防げます。今日はページ化の定義と最も一般的なページ化技術を紹介します。

ページネーションとは何か?

まずはページ化の基本的な概要から始めましょう。ページ化は、膨大な結果セットをより小さく管理しやすいチャンクに分割する技術です。簡単に言えば、ページ化とは大量のデータを複数の部分、つまり名前の通り「ページ」に分割することです。「なぜページ化を含めてコードを複雑にする必要があるのか?」と疑問に思う方もいるかもしれません。「なぜすべてのレコードをユーザーに渡して終わりにするという簡単な方法を取らないのか?」と。主な理由は二つあります。第一に、ページ付きテーブルで必要な情報をユーザーが見つけやすくなり、全体のユーザー体験が向上します。第二に、ページ化は返送される平均アイテム数を減らすのに役立ちます。データ配信の速度が向上するだけでなく、大量のデータ転送のためのリソース節約にもつながります。

フロントエンドページネーション vs. バックエンドページページ

ページネーションはフロントエンドとバックエンドの両方で起こり得ます。ページ化のアプローチに入る前に、フロントエンドとバックエンドのページ化を区別しなければなりません。フロントエンドページ化は、UI/UXデザインにより密接に関連して、ユーザーを読みやすい部分で視覚的に見せることに重点を置いています。一方で、バックエンドページ化の主な目的は、バックエンドサーバーの過負荷を避け、データ転送の効率を高めることです。フロントエンドのページ化と比べて、バックエンドのページ化は私たちエンジニアにとってより関連性が高いです。次のセクションでは主にバックエンドページ化技術を紹介します。(もしフロントエンドページ化にも興味があるなら、御社のUI/UXデザイナーとぜひ議論してください。彼らはこのトピックについて喜んで教えてくれるでしょう。)

バックエンドでのページ設定の実装方法は?

エンドポイントのページ化を実装する方法は多様です。ここでは、最も一般的なページ化技術のいくつかを取り上げます。

オフセットベースページ

オフセットベースのページ化は、最もシンプルなページ化技術の一つです。エンドポイントユーザーはオフセットと制限を活用して、エンドポイントに必要なデータページを伝えます。オフセットはターゲットデータの前でスキップすべきレコード数を示します。制限は1ページ上の最大レコード数を決定します。

ページ付きデータを取得するためのSQL文を作成する際には、これら2つのパラメータを直接利用できます。例えば、「users」テーブルからデータを取得したいとします。3ページ目のデータを取得したいとします。各ページには10のレコードが含まれています。この場合、目的のデータを得るために次のSQL文を書くことができます。

ユーザーから選択
ID ASCによる注文
リミット10
オフセット20;

制限は10です。なぜなら、1ページごとに「ユーザー」テーブルから10レコードしか取得できないからです。オフセットは20で、最初の2ページ(それぞれ10行)をスキップして、10レコードの3ページ目を取得する必要があるためです。

オフセットベースのページ設定の利点:

オフセットベースのページ化は、SQL文の作成に「offset」や「limit」を直接使えるため、実装が簡単です。複雑な論理は必要ありません。オフセットベースのページ化が実装されたエンドポイントのユーザーは、任意のページにジャンプすることができます。これはすべてのページ化技術に共通する普遍的な特性と考えることもできますが、後ほど示すように、一部のページ化技術にはこの特性がありません。

オフセットベースのページ設定のデメリット:

オフセットベースのページ割り当ては、特にオフセット数が多い場合に性能が低下します。理由は単純で、データベースはスキップすべき行(オフセット)をスキップし、最終的には破棄しなければならず、計算資源の無駄を生み出します。オフセットベースのページ割り当ては、結果が一貫性に欠ける傾向があります。その理由を示すために、以下の2つの例を挙げます。a. データ削除:ユーザーが最初のページを見ていると仮定します。誰かが最初のページからレコードを削除した場合です。すると、削除されたレコードのために2ページ目の最初のレコードが最初のページの最後のレコードになります。ユーザーが2ページ目に移動すると、元の最初のレコードは見えません。b. データ挿入:ユーザーが最初のページを閲覧していると仮定します。その場合、最初のページの最後のレコードは2ページ目に後ろ向きにシフトします。ユーザーが2ページ目に移動すると、最初のページの最後のレコードが再び表示されますが、これは本来あるべきではありません。

ページベースのページ割り当て

ページベースのページ番号は、基本的にオフセットベースのページ付けと同じです。唯一の違いは、ページベースのページ番号を使ってユーザーが現在閲覧しているページを追跡する点です。ページ番号をオフセットに変換するのは、以下の式で簡単にできます:

オフセット = (ページ番号 - 1) × 制限

カーソルベースのページ設定

カーソルベースのページ化は、カーソル、またはポインタを用いて、エンドポイントユーザーがカーソルで最後に見たレコードを追跡するページ化技術です。カーソルは通常、以下の情報を含みます:カーソルの位置と対応する値を識別するために使われる列(カーソルの一意性を確保するために少なくとも1つの一意列が必要)。これらの列に基づいて結果はどの順番(昇順か降順)でソートされるのか。エンドポイントユーザーがカーソルの前か後方に結果を求めるか。以下はその例です:

{
   「列」:[
      {
         「名前」:ニックネーム、
         「価値」:ショーン」
         「is_ascending」:本当だ
      },
      {
         「name」:id」、
         「Value」:23bf6f87-A4F5-4A9F-B441-1C98F7027E04",
         「is_ascending」:本当だ
      }
   ],
   "is_backward":false
}

このカーソルにより、ユーザーは次の列値を持つ行の後ろにあるニックネームとIDで昇順に並べたデータを取得できます。

ニックネーム欄:「ショーン」
ID列:「23bf6f87-a4f5-4a9f-b441-1c98f7027e04」

ニックネーム列だけを含めるだけでは不十分かもしれません。なぜなら、ニックネーム列には重複する値が含まれている可能性が高いからです。一意カーソルがなければ、データベースは要求されたデータを確実に特定できません。ID列を二次識別子として追加することで、カーソルの一意性が保証されます。

エンドポイントはページ付きデータとともに前後に移動するためのカーソルを計算・返す必要があり、エンドポイントユーザーがデータソース内のレコードを簡単にナビゲートできるようにします。

キューザーベースのページ付けの利点:

カーソルベースのページ化は、特にデータベースに多くのレコードがある場合、すべてのページ化技術の中で最も高い性能を示します。その理由は、オフセットベースのページ化とは異なり、カーソルベースのページ化は不要なデータをクエリして捨てる必要がないからです。カーソルを使うことで、カーソルベースのページ化は要求されたレコードを効率的に特定し取得できます。カーソルベースのページ化は、どの行を戻すべきかをオフセットで判断しないため、行の移動に耐性があります。古い行を削除したり新しい行を追加したりしても、カーソルベースのページ化は行を飛ばしたり、同じ行を2つの異なるページで表示したりしません。

カーソルベースのページ設定のデメリット

カーソルベースのページ付けの実装はかなり複雑です。(あまりに複雑なので、長くなりすぎないように別の技術ブログで詳しく説明する必要があると感じています。どうぞご期待ください!)

エンドポイントユーザーは、ナビゲーションが前後カーソルに依存しているため、特定のページにジャンプすることはできません。

どのページネーション技法を使うべきか?

経験則としては、ユーザー数の増加に伴いレコード数が指数関数的に増えることが予想されない場合や、ユーザーが任意のページにジャンプできるようにすることが重要な場合にオフセットベース(またはページベース)ページ割り当てを実装することです。それ以外の場合は、パフォーマンスが優れているためカーソルベースのページ割り当ての方が良い選択肢です。

概要

この記事では、ページ化が何をするのか、なぜそれが必要なのかを説明しました。次に、最もよく使われるページ化技術とそれぞれの利点と欠点を紹介しました。その後、どのページ化技術を使うべきかについてアドバイスをしました。この記事が、エンドポイントにページ化を実装するかどうか、またどのように実装するかについて十分な情報を提供したことを願っています。

Related Articles