FutureForgeFutureForge

خدمات FutureForge

  • طراحی و ساخت محصولاز شناخت نیاز تا انتشار محصول، یک مسیر روشن پیش رو دارید.
  • توسعه فول‌استکوب‌اپلیکیشن، API و داده را هماهنگ و یکپارچه توسعه دهید.
  • ممیزی مهندسیپیش از هزینه‌ی بیشتر، از وضعیت واقعی محصول‌تان باخبر شوید.
  • مشاوره معماریپیش از یک تصمیم فنی پرهزینه، گزینه‌ها را درست بسنجید.
  • زیرساخت و استقرارمحصول را با خیال راحت منتشر کنید و پایدار نگه دارید.
  • هوش مصنوعی در محصولهوش مصنوعی را فقط جایی به کار می‌گیریم که مسئله‌ای را حل کند.
نمونه‌کارهایادداشت‌هاقیمت‌گذاریدرباره ما
شروع گفتگو
  1. خانه
  2. /یادداشت‌ها
  3. /یادداشت‌ها
FutureForge

استودیوی مهندسی محصول — طراحی، ساخت و استقرار نرم‌افزار.

خدمات

طراحی سایت با وردپرستوسعه اختصاصیمهندسی محصولزیرساخت و استقرارمشاوره معماریهوش مصنوعی در محصول

راهنمای انتخاب

یادداشت‌هاقیمت‌گذاریتخمین هزینه پروژهمقایسه روش‌هانمونه‌کارهادرباره ماتماس

ارتباط

hello@futureforge.ir

ایده‌ای برای ساخت دارید؟

نیازتان را مطرح کنید تا درباره مسیر توسعه و قدم بعدی صحبت کنیم.

شروع گفتگو

© 2026 FutureForge. همه حقوق محفوظ است.

حریم خصوصیشرایط استفاده
خانهنمونه‌کارشروعتماس
معماری نرم‌افزار

طراحی pagination API: offset، cursor و ترتیب پایدار

سا
سهیل ابراهیم‌پور
·۲ آبان ۱۴۰۵·7 دقیقه مطالعه
APIpaginationcursoroffsetترتیب پایدار
طراحی صفحه‌بندی پایدار در API

pagination، filter و sort را در API پرترافیک طراحی کنید: offset یا cursor، ترتیب پایدار، توکن مات و سقف اندازهٔ صفحه؛ بر پایهٔ AIP-158 و مستندات PostgreSQL.

pagination اولین چیزی است که در API پرترافیک از کنترل خارج می‌شود: صفحه‌های عمیق کند می‌شوند، نتایج بین دو درخواست جابه‌جا می‌شوند و مصرف‌کننده‌ها یک کلاینت «همه را بگیر» می‌نویسند که دیتابیس را خسته می‌کند. این مقاله طراحی pagination، ترتیب پایدار، filter و sort را با تکیه بر راهنمای Google AIP-158، توضیح «No Offset» از Use The Index, Luke، مستندات PostgreSQL و مستندات pagination در Stripe می‌آورد (مراجعهٔ ۱۹ اکتبر ۲۰۲۶). ما سرویسی نساخته‌ایم و هیچ عدد سرعتی ادعا نمی‌کنیم؛ نتیجه به داده، شاخص‌ها و دیتابیس شما بستگی دارد. برای مفهوم API API چیست و معماری انتخاب معماری وب‌اپ را ببینید.

از ابتدا pagination بگذارید

AIP-158 می‌گوید endpointهای برگرداننده‌ی مجموعه باید از ابتدا pagination داشته باشند چون افزودن آن به متد موجود تغییر ناسازگار است؛ مجموعه‌ها بزرگ می‌شوند و زمان جست‌وجو و اندازهٔ پاسخ را بالا می‌برند. اگر امروز endpoint همه چیز را برمی‌گرداند، حتی برای «فقط ده مورد» هم از همین الان حد بگذارید (برای مهاجرت مقالهٔ نسخه‌بندی API را ببینید).

offset یا cursor؟

offset/limitcursor (keyset)
سادگیخیلی ساده، پرش به صفحهٔ دلخواهپیچیده‌تر، فقط «بعدی/قبلی»
هزینهٔ صفحهٔ عمیقردیف‌های ردشده باید خوانده شوند؛ OFFSET بزرگ ممکن است ناکارآمد باشد (PostgreSQL)شرط روی آخرین مقدار دیده‌شده؛ مستقل از عمق (Use The Index, Luke)
پایداری هنگام تغییر دادهدرج بین دو درخواست باعث تکرار یا جاافتادگی می‌شودجابه‌جایی نتایج را کم می‌کند
نیازORDER BY پایدارORDER BY پایدار و ستون‌های یکتا در ترتیب

Use The Index, Luke توضیح می‌دهد offset فقط تعداد ردیف‌های حذف‌شونده را می‌داند و بدون زمینه، پایگاه داده همان‌قدر ردیف را می‌خواند و دور می‌ریزد؛ و اگر ردیفی بین دو درخواست درج شود، صفحهٔ بعد ردیف تکراری می‌دهد. جایگزین، روش seek یا keyset است: یک شرط WHERE که فقط داده‌ای را انتخاب می‌کند که هنوز ندیده‌اید، مثلاً id < ?last_seen_id ORDER BY id DESC، و این روش می‌تواند حتی سریع‌تر باشد. مستندات PostgreSQL هم می‌گوید OFFSET بزرگ ممکن است ناکارآمد باشد چون ردیف‌های ردشده باید در سرور محاسبه شوند.

قاعدهٔ انتخاب (جمع‌بندی ما): برای مجموعه‌های بزرگ و پرتغییر یا فید بی‌پایان cursor؛ برای فهرست‌های کوچک و ثابت یا جاهایی که «برو صفحهٔ ۷» لازم است offset قابل‌قبول است، به شرط سقف عمق. هیچ‌کدام مطلق نیست و باید با داده و شاخص‌های خودتان بسنجید.

طراحی pagination API: offset، cursor و ت
نمودار مفهومی.

ترتیب پایدار

مستندات PostgreSQL صریح است: استفاده از مقادیر مختلف LIMIT و OFFSET بدون ORDER BY نتایج ناسازگار می‌دهد چون SQL بدون ORDER BY ترتیبی تضمین نمی‌کند؛ این باگ نیست و نتیجهٔ طبیعی ماهیت SQL است. پس: هر endpoint صفحه‌بندی‌شده یک ترتیب مشخص دارد و ستون‌هایش یکتا هستند. اگر بر اساس «تاریخ ایجاد» مرتب می‌کنید و چند ردیف تاریخ یکسان دارند، ستون یکتا (مثل id) را به‌عنوان tie-breaker اضافه کنید وگرنه بین صفحه‌ها ردیف جا می‌افتد یا تکرار می‌شود. برای sort توسط کاربر، فقط روی ستون‌هایی اجازه بدهید که شاخص دارند.

طراحی پارامترها و پاسخ

  • اندازهٔ صفحه: AIP-158 می‌گوید اندازهٔ صفحه اختیاری باشد، پیش‌فرض مستند داشته باشد، مقدار بزرگ‌تر از سقف به سقف کاهش یابد و مقدار منفی خطا بدهد؛ و API ممکن است کمتر از درخواست برگرداند (حتی صفر) بدون اینکه به انتهای مجموعه رسیده باشد. Stripe نمونه‌ای از سیاست مستند را دارد: limit بین ۱ و ۱۰۰ با پیش‌فرض ۱۰ در API نسخهٔ v1 (مقادیر خود Stripe است، توصیهٔ ما نیست).
  • توکن صفحهٔ بعد: AIP-158 توکن را «مات» (opaque) می‌داند و می‌گوید باقی پارامترها باید با درخواستی که توکن را صادر کرد یکی باشند؛ اگر فرق کنند خطا بدهید. مات بودن یعنی کلاینت ساختار آن را نمی‌فهمد و شما بعداً می‌توانید آن را تغییر دهید.
  • نشانهٔ پایان: AIP-158 می‌گوید توکن بعدی خالی تنها راه اعلام پایان مجموعه است. Stripe از has_more و شناسه‌های starting_after و ending_before استفاده می‌کند.
  • مجموع: total_size اختیاری است و می‌تواند تخمین باشد (باید مستند شود). شمارش دقیق روی جدول بزرگ گران است؛ در صورت نیاز تخمین یا بدون مجموع.

محدودیت‌ها

  1. سقف اندازهٔ صفحه را سمت سرور اعمال کنید و مقدار را مستند کنید؛ مقدار خاص تیم شما را با اندازهٔ پاسخ و زمان واقعی تعیین کنید.
  2. برای offset سقف عمق بگذارید (مثلاً بیشتر از N رد نکن) یا کاربر را به cursor هدایت کنید.
  3. برای filterها فقط روی ستون‌های دارای شاخص اجازه بدهید و فهرست مجاز را مستند کنید.
  4. پیمایش کامل (export) را به endpoint یا کار جداگانه (کار پس‌زمینه) منتقل کنید تا ترافیک عادی را تحت تأثیر نگذارد.
  5. انقضای توکن را در مستندات بگویید؛ AIP-158 بحث توکن‌های منقضی‌شونده را دارد.

آزمون

  1. داده‌ای با ترتیب یکسان در چند ردیف (مثلاً تاریخ مشابه) بسازید و همهٔ صفحه‌ها را پیمایش کنید؛ باید هر ردیف دقیقاً یک بار بیاید.
  2. در میانهٔ پیمایش یک ردیف جدید درج کنید و رفتار offset را با cursor مقایسه کنید.
  3. اندازهٔ صفحهٔ بزرگ‌تر از سقف و منفی را بفرستید و پاسخ را با مستندات تطبیق دهید.
  4. زمان صفحهٔ اول و صفحهٔ عمیق را روی حجم داده نزدیک تولید اندازه بگیرید و با EXPLAIN شاخص را بررسی کنید.
  5. تغییر پارامتر هنگام استفاده از توکن را بفرستید و خطا را ببینید.

مثال ساختگی: فهرست سفارش‌ها

فرض کنید endpoint فهرست سفارش‌ها بر اساس تاریخ ایجاد و سپس شناسه (برای شکستن تساوی) مرتب شده است. درخواست اول بدون توکن می‌آید و N ردیف برمی‌گردد (N همان اندازهٔ پیش‌فرض مستند شما)؛ پاسخ شامل فهرست و یک توکن مات برای صفحهٔ بعد است. داخل توکن، مقدار تاریخ و شناسهٔ آخرین ردیف رمزگذاری یا کدگذاری شده، و سرور برای صفحهٔ بعد شرطی مثل «تاریخ کمتر، یا تاریخ برابر و شناسه کمتر» را اعمال می‌کند. اگر کلاینت همراه توکن، filter متفاوتی بفرستد، سرور خطای پارامتر ناسازگار می‌دهد. این طراحی کمک می‌کند ردیف تکراری یا جاافتاده نداشته باشید، ولی باید با آزمون روی داده‌ای شبیه تولید و بررسی شاخص مرکب (تاریخ و شناسه) تأیید شود. مثال آموزشی است و عددی ندارد.

اگر محصول به «رفتن به صفحهٔ ۷» نیاز دارد، می‌توانید offset را برای فهرست‌های کوچک و ثابت نگه دارید و برای فهرست‌های بزرگ cursor ارائه دهید؛ ولی دو رفتار را در مستندات شفاف جدا کنید تا مصرف‌کننده بداند هر endpoint چه رفتاری دارد.

اشتباهات رایج

  • نداشتن ORDER BY یا نداشتن ستون یکتا در ترتیب.
  • offset بدون سقف عمق روی جدول بزرگ.
  • برگرداندن مجموع دقیق گران برای هر صفحه.
  • افشای ساختار توکن و وابسته شدن کلاینت به آن.
  • افزودن pagination بعد از انتشار بدون مهاجرت.
  • اجازهٔ sort و filter روی ستون بدون شاخص.
  • استفاده از یک endpoint برای export کامل.

چک‌لیست

  1. هر مجموعه از ابتدا pagination دارد.
  2. ترتیب پایدار با ستون یکتا تعریف شده است.
  3. نوع pagination (offset یا cursor) با دلیل انتخاب شده است.
  4. سقف اندازهٔ صفحه و عمق مستند و اعمال شده است.
  5. توکن مات است و پارامترها با آن سازگار بررسی می‌شوند.
  6. filter و sort فقط روی ستون‌های دارای شاخص مجازند.
  7. آزمون تکرار/جاافتادگی و عملکرد صفحهٔ عمیق انجام شده است.

منابع و مراجع

  • AIP-158: Pagination — Google API Improvement Proposals، 2026-10-19.
  • We need tool support for keyset pagination (No Offset) — Use The Index, Luke، 2026-10-19.
  • LIMIT and OFFSET — PostgreSQL Documentation، 2026-10-19.
  • Pagination (Stripe API) — Stripe Docs، 2026-10-19.

نویسنده

سا

سهیل ابراهیم‌پور بنیان‌گذار FutureForge است. روی طراحی محصول، معماری و استقرار نرم‌افزار سفارشی کار می‌کند.

یادداشت‌های مرتبط

یادداشت‌های مرتبط

دسته‌بندی‌ها

خدمات مرتبط

از یادداشت تا پروژه

اگر با مسئله‌ای شبیه این روبه‌رو هستید، درباره‌ی شرایط پروژه‌تان با هم صحبت کنیم.

برای انتخاب مسیر فنی پروژه‌تان کمک می‌خواهید؟

از مسئله و محدودیت‌هایتان بگویید؛ اگر بتوانیم همراهی‌تان کنیم، برای گفت‌وگو هماهنگ می‌کنیم.

سهیل ابراهیم‌پور
یادداشت‌ها
خواندن EXPLAIN ANALYZE در PostgreSQL
تفاوت Nginx و Apache: چارچوب تصمیم
SQL یا NoSQL: انتخاب بر اساس workload، query و سازگاری
تفاوت CRM و Help Desk در مدل داده
ERP آماده یا اختصاصی؟ تصمیم بر پایهٔ هزینهٔ نگه‌داری

معماری نرم‌افزار

خواندن EXPLAIN ANALYZE در PostgreSQL

۲ آبان ۱۴۰۵

معماری نرم‌افزار

تفاوت Nginx و Apache: چارچوب تصمیم

۲ آبان ۱۴۰۵

معماری نرم‌افزار

SQL یا NoSQL: انتخاب بر اساس workload، query و سازگاری

۲ آبان ۱۴۰۵

معماری نرم‌افزار

تفاوت CRM و Help Desk در مدل داده

۲ آبان ۱۴۰۵

معماری نرم‌افزار

ERP آماده یا اختصاصی؟ تصمیم بر پایهٔ هزینهٔ نگه‌داری

۲ آبان ۱۴۰۵
همه یادداشت‌ها294
معماری نرم‌افزار22
واژه‌نامه37
عملیات و استقرار90
مهندسی محصول117
راهنمای وب28
طراحی و ساخت محصول
توسعه فول‌استک
ممیزی مهندسی
مشاوره معماری
زیرساخت و استقرار
شروع گفتگو
ابزارهای رایگان
شروع گفتگو