পাঠ্যক্রম খুলুন
প্রাথমিক পর্যায়

Pagination: বড় তালিকা ছোট অংশে পড়া

Pagination and API Resources

এই পাঠের কুইজ ↓৬ মিনিট পড়াPHP 8.3+ · Laravel 12
এই পাঠের সূচিপত্র

এই পাঠে যা শিখবেন

  • Offset, simple ও cursor pagination
  • Stable ordering ও bounded page size
  • Laravel resource serialization

সমস্যা দিয়ে শুরু

API প্রতিবার সব order ফেরায়। শুরুতে শত row, পরে লক্ষ row হওয়ায় memory ও response time বেড়ে যায়। Pagination output ছোট করে। কিন্তু user পরের page দেখতে দেখতে নতুন order ঢুকলে offset-based listing-এ duplicate বা skipped item দেখা যেতে পারে। তাই শুধু limit বসালেই contract সম্পূর্ণ হয় না।

সহজ করে বুঝি

Offset pagination row skip করে page number দেয়; deep offset expensive হতে পারে। Total count query আলাদা cost যোগ করে। Simple pagination total count বাদ দিয়ে next/previous জানায়। Cursor pagination ordered column values ধরে পরের range পড়ে; stable unique ordering ও suitable index দরকার। Cursor সাধারণত arbitrary page 500 jump-এর সুবিধা দেয় না। Concurrent update ordering field বদলালে cursor-ও magic snapshot নয়। Authorization filter প্রতিটি page-এ একই scope-এ থাকতে হবে।

পরিচিত একটি উপমা

খাতার ২০০ নম্বর পৃষ্ঠা খুলতে offset, আর শেষ দেখা receipt number-এর পর থেকে পড়তে cursor। নতুন receipt খাতার সামনে যোগ হলে page position সরে যায়; stable receipt identity ধরে এগোলে সেই সমস্যা কমে। তবে পুরোনো receipt-এর নম্বর বদলালে continuity আবার নষ্ট হয়।

নকশাটি দেখুন

Diagram লোড হচ্ছে…

Client cursor ও page size দেয়, server max size enforce করে।
Diagram-এর text flow দেখুন
flowchart LR
 C[Client cursor and bounded limit] --> Q[Authorized indexed order query]
 Q --> P[Fetch next ordered rows]
 P --> R[Resource representation]
 R --> N[Data and next cursor]

Client cursor ও page size দেয়, server max size enforce করে। Query user scope এবং deterministic order দিয়ে bounded rows পড়ে। Resource শুধু public contract-এর fields রাখে। Next cursor client-এর কাছে opaque navigation token; এটিকে authorization credential ধরে নেওয়া যাবে না। অন্য user cursor দিলেও server filter বাদ যাবে না।

PHP ও Laravel-এ প্রয়োগ

Controller-method fragment; authenticated user, Order model ও database index on user_id,id আছে ধরে নেওয়া হয়েছে। OrderResource আগেই তৈরি; তার toArray method-এ id/status/created_at-এর মতো explicit fields রাখুন। Laravel cursor string input নিজে decode করে; client arbitrary offset দেয় না।

php
use App\Http\Resources\OrderResource;
use Illuminate\Http\Request;

public function index(Request $request)
{
    $input = $request->validate([
        'per_page' => ['sometimes', 'integer', 'min:1', 'max:50'],
    ]);
    $orders = $request->user()->orders()
        ->orderBy('id')
        ->cursorPaginate($input['per_page'] ?? 20);

    return OrderResource::collection($orders);
}

সুবিধা, সীমাবদ্ধতা ও trade-off

Offset page numbers user-friendly, তবে deep traversal ও count cost বড় হতে পারে। Cursor large sequential feed-এ কার্যকর, arbitrary jump ও exact totals কঠিন। Stable snapshot export দরকার হলে pagination-এর বাইরে snapshot boundary বা cutoff ID/time রাখা যায়। Data retention চলার সময় deleted rows, edits ও insertion handling documentation-এ লিখুন। Index ছাড়া cursor query-ও full scan করতে পারে।

সাধারণ ভুল

  • User-দেওয়া unlimited per_page গ্রহণ করা।
  • Unique tie-breaker ছাড়া timestamp দিয়ে cursor করা।
  • Pagination করার পরে memory-তে authorization filter লাগানো।

আরও একটু গভীরে

Ordering created_at হলে একই timestamp-এ বহু row থাকতে পারে; id tie-breaker দিন এবং composite index যাচাই করুন। Nullable বা expression ordering-এর driver/framework limitations পরীক্ষা করুন। Resource relation serialize করার সময় lazy loading N+1 বানাতে পারে; bounded eager loading এবং relation-specific authorization দরকার। Cursor token encrypted বা encoded হলেই trusted input হয়ে যায় না; query scope server-এ স্থির রাখুন।

মনে রাখুন

Pagination হলো performance ও consistency contract। Bounded page size, stable order এবং database index একসঙ্গে রাখুন। Cursor navigation permission-এর বিকল্প নয়।

নিজে চেষ্টা করুন

দুটি browser session-এ একই order list খুলুন। প্রথম page-এর পরে নতুন order insert করে offset ও cursor-এর পরের page তুলনা করুন। Duplicate, omission ও index plan লিখে রাখুন; total count requirement সত্যিই দরকার কি না বিচার করুন।

নিজের বোঝা যাচাই করুন

1. Cursor কি page number?

না। এটি শেষ দেখা ordered values থেকে পরের range চিহ্নিত করে। Client সাধারণত token opaque রেখেই next link ব্যবহার করে।

2. Unique order কেন?

একই ordered value-র বহু row থাকলে boundary ambiguity হয়। Unique tie-breaker predictable traversal সাহায্য করে।

3. Count বাদ দিলে লাভ?

Large filtered dataset-এ exact total query ব্যয়বহুল হতে পারে। Simple/cursor pagination সেই cost এড়াতে পারে, workload অনুযায়ী।

4. Cursor data access দেয়?

না। Server-side user/tenant scope প্রতিটি query-এ লাগবে। অন্যের cursor দিয়ে অন্যের row দেখা যাবে না।

5. Pagination N+1 ঠেকায়?

নিজে নয়। Page-এর প্রতিটি model relation lazy load করলে বহু query হয়; eager load ও serialization review দরকার।

আরও পড়ুন

এই পাঠের কুইজ

এই পাঠ থেকে ২টি প্রশ্ন। উত্তর দিয়ে ব্যাখ্যা দেখুন; অধ্যায়ের কুইজ আলাদাভাবে দিতে হবে।

এই পাঠের ২টি প্রশ্নের উত্তর দিন। পাস করতে দুটিই সঠিক হতে হবে।

জমা দেওয়ার পর সঠিক উত্তর ও ব্যাখ্যা দেখবেন। ফলাফল এই ব্রাউজারে সংরক্ষিত থাকবে। অনুশীলনের ফল অধ্যায় সম্পন্নের হিসাবে যোগ হয় না।

সব বিষয় মিলিয়ে অনুশীলন করুন →

অগ্রগতি এই ব্রাউজারে সংরক্ষিত থাকে। শুধু পাঠ খুললে সম্পন্ন হয় না।