SELECT u.id, u.date, u.note, u.user_id
FROM user_notes AS u
WHERE u.date < @date OR (u.date = @date AND u.id <= @lastId)
ORDER BY u.date DESC, u.id DESC
LIMIT @limit;
💡توجه کنید که هیچ OFFSET در کوئری وجود ندارد. ما مستقیماً بر اساس cursor به دنبال ردیفها میگردیم که کارآمدتر است.
محدودیتهای Cursor Pagination: ❌
• اگر کاربران نیاز به تغییر داینامیک فیلدهای مرتبسازی داشته باشند، پیادهسازی به شدت پیچیده میشود.
• کاربران نمیتوانند به یک شماره صفحه خاص بپرند.
• پیادهسازی صحیح آن پیچیدهتر است.
بررسی پلنهای اجرای SQL 📊
من پلنهای اجرا را برای هر دو مقایسه کردم. برای صفحهای در عمق دیتابیس (آفست ۹۰۰,۰۰۰):
زمان اجرای Offset Pagination: 704.217 ms 🐢
زمان اجرای Cursor Pagination: 40.993 ms 🚀
یک بهبود عملکرد ۱۷ برابری با cursor pagination!
افزودن ایندکس برای Cursor Pagination 🔑
من همچنین تأثیر ایندکسها را روی cursor pagination تست کردم. یک ایندکس ترکیبی روی فیلدهای Date و Id ایجاد کردم.
نتیجه اولیه کندتر بود! اما با استفاده از مقایسه تاپل (tuple comparison) در SQL:
WHERE (u.date, u.id) <= (@date, @lastId)
زمان اجرا به 0.668 ms کاهش یافت! ⚡️
برای ترجمه این به EF Core، میتوانید از EF.Functions.LessThanOrEqual که یک ValueTuple را به عنوان آرگومان میپذیرد، استفاده کنید.
خلاصه 📝
با اینکه offset pagination سادهتر است، در مقیاس بالا دچار افت عملکرد شدید میشود. Cursor pagination عملکرد ثابتی را حفظ میکند و برای فیدهای real-time و infinite scroll عالی است.
🤔چه زمانی از کدام استفاده کنیم؟
🔹 برای APIهای حساس به عملکرد، فیدهای real-time یا infinite scroll از ⟵ Cursor pagination
🔹 برای اینترفیسهای ادمین، مجموعه دادههای کوچک، یا زمانی که به تعداد کل صفحات نیاز دارید ⟵ Offset pagination.
🔖 هشتگها:
#CSharp #DotNet #Pagination #Performance #SystemDesign