فهرست یک API ممکن است در صفحهٔ اول سریع و قابل فهم باشد، اما با بیشتر شدن داده‌ها رفتار مبهمی پیدا کند. کاربر صفحهٔ بعد را باز می‌کند و یک رکورد دوباره دیده می‌شود؛ یا رکوردی که چند لحظه پیش وارد شده، جای بقیه را تغییر می‌دهد. انتخاب میان OFFSET و صفحه‌بندی بر اساس کلید، به نوع پیمایش، ترتیب و تغییر داده وابسته است. این مقاله یک روش پیشنهادی برای تصمیم‌گیری ارائه می‌کند و هیچ نتیجهٔ سرعتی را بدون اندازه‌گیری به سامانه‌ای نسبت نمی‌دهد.

مثال ما یک فهرست فرضی رویداد با زمان ایجاد و شناسهٔ یکتا است. فرض می‌کنیم هر دو مقدار تهی نیستند و ترتیب نمایش نزولی است. مستندات رسمی PostgreSQL دربارهٔ LIMIT و OFFSET، مقایسهٔ ردیف‌ها و ایندکس و ترتیب مبنای نکات فنی این راهنما هستند؛ جزئیات طراحی API پیشنهاد مقاله‌اند.

۱. ترتیب پایدار و هدف پیمایش را مشخص کنید

پیش از انتخاب روش، تجربهٔ مورد انتظار را بنویسید. آیا کاربر باید به صفحهٔ شمارهٔ بیست برود یا فقط بعدی و قبلی را می‌بیند؟ آیا فهرست یک گزارش ثابت است یا داده‌های تازه مرتب وارد آن می‌شوند؟ پاسخ این پرسش‌ها تعیین می‌کند که شمارهٔ صفحه، نشانگر ادامه یا یک خروجی مستقل برای گزارش مناسب‌تر است. هیچ روش واحدی همهٔ این نیازها را بدون هزینه و محدودیت برآورده نمی‌کند.

ترتیب رویدادهای هم‌زمان با شناسهٔ یکتا و هدف پیمایش
تصویر مفهومی: زمان مساوی به یک کلید متمایزکنندهٔ روشن نیاز دارد.

در مثال رویدادها، مرتب‌سازی فقط با زمان کافی نیست، چون چند رویداد می‌توانند زمان یکسان داشته باشند. پیشنهاد ما استفاده از زمان و شناسهٔ یکتا به عنوان زوج مرتب‌سازی است. این زوج باید در پرس‌وجو و نشانگر ادامه معنای یکسانی داشته باشد. تغییر ترتیب از جدیدترین به قدیمی‌ترین در میانهٔ پیمایش، بدون شروع مسیر تازه، نشانگر قبلی را مبهم می‌کند.

مستندات PostgreSQL بر اهمیت ORDER BY برای نتیجهٔ قابل پیش‌بینی با LIMIT تأکید می‌کند. این قاعده به‌تنهایی فهرست زنده را به تصویری ثابت از داده تبدیل نمی‌کند. اگر کاربر باید دقیقاً داده‌های یک لحظه را برای حسابرسی ببیند، نیاز به طراحی ثبات مشاهده جداگانه دارید. در قرارداد API روشن کنید که پیمایش معمولی چه تضمینی دربارهٔ داده‌های هم‌زمان ارائه می‌دهد و چه تضمینی ارائه نمی‌دهد.

۲. OFFSET را با هزینه و تغییر جای رکوردها بسنجید

در روش OFFSET، برنامه تعدادی رکورد را کنار می‌گذارد و بخش بعدی را برمی‌گرداند. این مدل برای شمارهٔ صفحه قابل فهم است و در فهرست کوچک می‌تواند انتخاب عملی باشد. با این حال، مستندات توضیح می‌دهد که ردیف‌های کنارگذاشته‌شده نیز در سرور محاسبه می‌شوند. از این نکته نباید یک عدد سرعت یا نتیجهٔ قطعی برای همهٔ پرس‌وجوها استخراج کرد؛ حجم، فیلتر و برنامهٔ اجرای پرس‌وجو مهم‌اند.

تغییر مرز صفحهٔ OFFSET پس از ورود رویداد تازه
تصویر مفهومی: در فهرست زنده، جای رکوردها می‌تواند میان دو درخواست تغییر کند.

در فهرست زنده، اضافه شدن یک رویداد در ابتدای ترتیب می‌تواند جای رکوردهای صفحات بعد را جابه‌جا کند. اگر صفحهٔ دوم با تعداد ثابتِ کنارگذاشته‌شده خوانده شود، مرز جدید لزوماً ادامهٔ همان مرز قبلی نیست. پیشنهاد آزمایش ما این است که بین دو درخواست، یک رکورد تازه اضافه و یک رکورد از محدودهٔ قبلی حذف کنید؛ سپس تکرار یا جاافتادگی را مطابق قرارداد مورد انتظار بررسی کنید.

اگر محصول به شمارهٔ صفحه نیاز دارد، حذف این قابلیت صرفاً برای استفاده از یک روش مشهور تصمیم کاملی نیست. شاید محدود کردن عمق پیمایش، فیلتر دقیق‌تر یا گزارش جدا راه مناسب‌تری باشد. این تصمیم باید با رفتار واقعی کاربر سنجیده شود. تعداد کل رکوردها نیز درخواست مستقلی است و نباید هزینهٔ محاسبهٔ آن در ارزیابی صفحه‌بندی نادیده بماند.

۳. نشانگر ادامه را از آخرین کلید بسازید

در روش مبتنی بر کلید، درخواست بعدی از مقدار آخرین رکورد صفحهٔ قبلی ادامه پیدا می‌کند. برای مثال نزولی با زمان و شناسهٔ غیرتهی، یک مقایسهٔ زوجیِ کوچک‌تر می‌تواند مرز ادامه را نشان دهد؛ ترتیب پرس‌وجو نیز باید همان زمان و شناسهٔ نزولی باشد. این توضیح یک الگوی محدود برای فرض‌های مقاله است، نه نسخهٔ آماده برای هر ترکیب صعودی، نزولی یا مقدار تهی.

نشانگر ادامه بر اساس زمان و شناسهٔ آخرین ردیف
تصویر مفهومی: شرط ادامه و ترتیب پرس‌وجو باید معنای یکسانی داشته باشند.

PostgreSQL مقایسهٔ زوجی را برای عملگرهای مناسب از چپ به راست انجام می‌دهد؛ وجود مقدار تهی در نقطهٔ تعیین‌کننده می‌تواند نتیجه را نامعلوم کند. بنابراین در قرارداد پیشنهادی، غیرتهی بودن کلیدها روشن است. اگر دادهٔ واقعی شما زمان تهی دارد یا ترتیب چند ستون هم‌جهت نیست، شرط ادامه را جدا طراحی و با نمونه‌های مرزی آزمون کنید. کپی کردن یک شرط ساده بدون این بررسی می‌تواند رکوردها را حذف کند.

نشانگر بهتر است علاوه بر کلید آخر، به تنظیمات همان فهرست وابسته باشد. فیلتر وضعیت، جهت مرتب‌سازی و نسخهٔ قرارداد را در اعتبار آن لحاظ کنید. رمزگذاری سادهٔ متن، مجوز دسترسی یا حفاظت از تغییر مقدار ایجاد نمی‌کند. سرور باید نشانگر را بررسی کند و همچنان دسترسی کاربر به داده‌های درخواست بعدی را مستقل کنترل کند.

۴. ایندکس و اندازهٔ صفحه را با دادهٔ نماینده بررسی کنید

وجود ایندکس با ترتیب مناسب می‌تواند به بعضی پرس‌وجوهای مرتب‌شده کمک کند، اما انتخاب برنامهٔ اجرا به شرایط داده وابسته است. مستندات PostgreSQL توضیح می‌دهد که برای خواندن بخش بزرگی از جدول، مرتب‌سازی جدا ممکن است از پیمایش ایندکس مناسب‌تر باشد. بنابراین پیشنهاد مقاله، بررسی برنامهٔ اجرا روی دادهٔ نماینده و پرس‌وجوی واقعی همراه فیلترهای آن است.

بررسی برنامهٔ پرس‌وجو، ایندکس و اندازهٔ پاسخ صفحه
تصویر مفهومی: هزینه و سرعت با داده و شرایط نماینده سنجیده می‌شوند.

اندازهٔ صفحه را نیز با نیاز پاسخ و مصرف‌کننده تنظیم کنید. صفحهٔ بسیار بزرگ فقط مسئلهٔ پایگاه داده نیست؛ انتقال شبکه، تبدیل داده و نمایش رابط کاربری را هم سنگین می‌کند. مقدار مجاز و سقف اندازه را در سرور کنترل کنید. در آزمون پیشنهادی، اندازه‌های متفاوت با همان فیلتر و ترتیب بررسی می‌شوند و زمان پاسخ، حجم خروجی و رفتار مصرف‌کننده جدا ثبت می‌شوند.

برای سنجش منصفانه، شرایط مقایسه را یکسان نگه دارید. داده، تعداد اتصال‌ها، گرم یا سرد بودن کش و ترکیب فیلترها را ثبت کنید. آزمون یک پرس‌وجوی ساده روی جدول خالی، برای نتیجه‌گیری دربارهٔ فهرست سازمانی کافی نیست. اگر هنوز دادهٔ نماینده ندارید، گزارش را آزمایش اولیه بنامید و محدودیتش را روشن کنید؛ عدد آزمایشی نباید به وعدهٔ محصول تبدیل شود.

۵. حذف، تغییر کلید و پایان فهرست را آزمون کنید

آخرین صفحه فقط یک حالت نیست. فهرست خالی، صفحهٔ کامل بدون ادامه، نشانگر منقضی و رکورد مرزی حذف‌شده را بررسی کنید. مشخص کنید مصرف‌کننده چگونه پایان فهرست را تشخیص می‌دهد. در طراحی پیشنهادی، وجود نشانگر ادامه یک تصمیم صریح در پاسخ است؛ رابط کاربری نباید صرفاً از تعداد رکوردها حدس بزند که صفحهٔ دیگری حتماً وجود دارد.

آزمون مرزها، نشانگر نامعتبر و پایان فهرست
تصویر مفهومی: رفتار حذف، تغییر فیلتر و پایان فهرست بخشی از قرارداد API است.

تغییر کلید مرتب‌سازی پس از خواندن صفحه نیز نیاز به تصمیم دارد. اگر زمانِ مرتب‌سازی قابل ویرایش باشد، رکورد می‌تواند از یک سوی مرز به سوی دیگر برود. صفحه‌بندی بر اساس کلید به‌تنهایی این حرکت را خنثی نمی‌کند. در مثال ما، زمان ایجاد ثابت فرض شده است؛ سامانه‌ای که با زمان ویرایش مرتب می‌شود باید رفتار پیمایش زنده را جدا توضیح دهد.

پیش از انتشار API، چند سناریوی کوتاه را با نتیجهٔ مورد انتظار ثبت کنید: زمان‌های مساوی، افزودن دادهٔ تازه، حذف رکورد، تغییر فیلتر و درخواست با نشانگر نامعتبر. انتخاب مناسب روشی است که نیاز پیمایش را برآورده کند و محدودیتش برای مصرف‌کننده روشن باشد. سرعت مهم است، اما ترتیب قابل فهم، کنترل دسترسی و رفتار مرزها نیز بخشی از کیفیت همان API هستند.

برای پیگیری علت شکست نشانگر ادامه در اجرای واقعی، روش گزارش رویداد سرور را نیز بررسی کنید؛ ثبت مرحله و کد خطا می‌تواند به بررسی مسئله کمک کند، بدون آنکه متن کامل داده‌های کاربر ذخیره شود.

منابع و مطالعهٔ بیشتر

بررسی منابع: ۲۲ مهر ۱۴۰۵. تحلیل‌ها و پیشنهادهای اجرایی، جمع‌بندی نویسنده‌اند.