Offset Pagination — ofsetlə paginasiya — HTTP API vasitəsilə məlumatların səhifələrlə yüklənməsi metodudur. Müştəri offset (başlanğıcdan yerdəyişmə) və limit (səhifə ölçüsü) parametrlərini ötürür, server isə offset mövqeyindən qeydləri qaytarır. REST API Tutorial-a görə, bu yanaşma sadə tətbiqinə görə RESTful xidmətlərində geniş istifadə olunur. Lakin böyük həcmli məlumatlarda offset-paginasiya cədvəlin tələb olunan mövqeyə qədər tam skan edilməsi səbəbindən performansını itirir.
Əsas məqamlar
Offset Pagination — müştəri sorğusunun iki parametr ehtiva etdiyi məlumatların səhifələrə bölünməsi metodudur: offset (neçə qeydin atlanacağı) və limit (neçə qeydin qaytarılacağı). Server OFFSET və LIMIT ilə SQL sorğusu icra edir, göstərilən sayda sətri atlayır və sabit ölçülü nəticə dəstini qaytarır.
Metod relyasiyalı verilənlər bazalarında səhifələr üzrə naviqasiyanın ən sadə yolu kimi yaranmış və REST arxitekturasının inkişafı ilə HTTP API-ya köçürülmüşdür. Offset Pagination serverdə vəziyyətin saxlanmasını tələb etmir — hər sorğu müstəqildir və seçim üçün bütün məlumatları ehtiva edir.
Postman (2025) tərəfindən API dizaynı tədqiqatına görə, offset-paginasiya ictimai REST API-ların 72%-də istifadə olunur ki, bu da onu böyük həcmli məlumatlarda məlum performans məhdudiyyətlərinə baxmayaraq dominant standart edir.
Offset Pagination ilə tipik REST sorğusu offset və limit sorğu parametrlərini ehtiva edir. Cavab tələb olunan səhifənin qeydlərinin siyahısını və naviqasiya interfeysi qurmaq üçün metadata ehtiva edir.
Limit parametri qaytarılan qeydlərin sayını məhdudlaşdırır və serveri və müştərini həddindən artıq yükdən qoruyur. Tipik limit dəyərləri məlumatların mürəkkəbliyindən asılı olaraq səhifə başına 10-dan 50-yə qədərdir.
data class PageRequest(
val offset: Int,
val limit: Int
)
data class PageResponse<T>(
val items: List<T>,
val total: Int,
val hasMore: Boolean
)
fun RetrofitApi.fetchPage(request: PageRequest): Call<PageResponse<Item>>
Offset Pagination OFFSET və FETCH NEXT (və ya MySQL/SQLite-də LIMIT) konstruksiyaları ilə SQL sorğusuna çevrilir. Verilənlər bazası serveri cədvəli skan edir, offset-ə bərabər sayda sətri atlayır və növbəti limit sətrini qaytarır. Offset nə qədər böyükdürsə, sorğu bir o qədər uzun çəkir.
Performans problemi onunla bağlıdır ki, verilənlər bazası birbaşa offset mövqeyinə keçə bilmir — bütün əvvəlki sətirləri oxumalı və atmalıdır. Offset = 100000 və limit = 20 olduqda DBMS 100020 sətir oxuyacaq və yalnız 20-ni qaytaracaq.
SQL — serverin offset-paginasiyanı icra etdiyi dildir. PostgreSQL və MySQL-də LIMIT, SQL Server və Oracle-da OFFSET...FETCH istifadə olunur. Müxtəlif DBMS-lər bu sorğunu özünəməxsus şəkildə optimallaşdırır, lakin skan etmənin əsas problemi eyni qalır.
SELECT id, title, created_at
FROM articles
ORDER BY created_at DESC
OFFSET 100000 ROWS
FETCH NEXT 20 ROWS ONLY;
Məlumat ardıcıllığı — dinamik dəstlərlə işləyərkən Offset Pagination-ın əsas çatışmazlığı. İstifadəçinin iki sorğusu arasında cədvəlin əvvəlinə yeni qeyd əlavə edilərsə, bütün mövcud qeydlər yerdəyişir. İstifadəçi dublikatlar və ya atlamalar görür.
Təsəvvür edək ki, limit = 20 olan 100 qeyddən ibarət cədvəl var. Səhifə 1-də istifadəçi 1-20 qeydlərini görür. Administrator 5 yeni qeyd əlavə edir. Səhifə 2-də istifadəçi gözlənilən 21-40 əvəzinə 26-45 qeydlərini görür — 21-25 qeydləri atlanıb və əvvəlki dəstdən 21-25 qeydləri səhifə 1-də təkrarlanıb.
Cursor-based pagination — cari səhifənin son qeydinə işarəçidən istifadə edən Offset Pagination-a alternativdir. Rəqəmsal yerdəyişmə əvəzinə müştəri son alınan qeydin identifikatorunu ötürür, server isə ondan sonrakı N qeydi qaytarır.
Cursor-based yanaşma ardıcıllıq problemini həll edir: kursorun mövqeyi əlavə və ya silmələr zamanı dəyişmir, çünki kursor mövqeyə deyil, konkret qeydə istinad edir. Lakin tətbiqi daha mürəkkəbdir — unikal sıralana bilən sahə tələb olunur (adətən ID və ya timestamp).
| Parametr | Offset Pagination | Cursor-based Pagination |
|---|---|---|
| Sadəlik | Yüksək — iki rəqəmsal parametr | Orta — kursorun kodlaşdırılması tələb olunur |
| Ardıcıllıq | Aşağı — əlavələr zamanı dublikatlar | Yüksək — kursor dəyişikliklərdən asılı deyil |
| Performans | Offset artdıqca azalır | İstənilən həcmdə sabit |
| Səhifəyə atlama | Bəli — istənilən səhifəyə keçmək olar | Xeyr — yalnız ardıcıl naviqasiya |
| Uyğundur | <10K qeyd cədvəlləri, səhifə nömrələri olan UI | Feed-lər, sonsuz skroll, böyük dəstlər |
Yanaşmalar arasında seçim istifadəçinin interfeys tələblərindən asılıdır. Səhifə nömrələri və birbaşa keçid ilə naviqasiya lazımdırsa — Offset Pagination daha sadədir. Sonsuz skroll və ya xəbər feed-ləri üçün kursorlar daha üstündür.
Keyset pagination — OFFSET əvəzinə WHERE ilə unikal açar üzrə filtrləmənin aparıldığı cursor-based yanaşmasının bir növüdür. SQL sorğusu WHERE id > lastId şərtindən istifadə edir ki, bu da verilənlər bazasına atılmış sətirləri skan etmədən indeksdən istifadə etməyə imkan verir.
PostgreSQL Wiki-yə görə, keyset pagination böyük yerdəyişmələrdə offset sorğusundan 100-1000 dəfə sürətlidir, çünki indeks skan etmə cədvəlin tam gəzintisini əvəz edir. Çatışmazlıq — ardıcıl keçid olmadan ixtiyari səhifəyə atlamağın mümkünsüzlüyü.
Offset Pagination kiçik və orta həcmli məlumat dəstləri üçün (10000 qeydə qədər) optimaldır, burada istifadəçiyə səhifə nömrələri olan interfeys lazımdır. Tipik ssenarilər — admin panellər, sifariş siyahıları, filtrləmə və səhifələr üzrə paginasiya ilə kataloqlar.
Mobil tətbiqlər üçün offset-paginasiya yeni qeydlərin əlavə edilməsinin nadir və ya qeyri-mümkün olduğu tarixi məlumatların yüklənməsi zamanı uyğundur — məsələn, istifadəçinin sifariş tarixçəsi, tamamlanmış tapşırıqların siyahısı, əməliyyat arxivi. Bu ssenarilərdə ardıcıllıq problemi yaranmır.
Tövsiyə edilmir Offset Pagination-ın sosial media feed-ləri, şərh siyahıları, çatlar və tez-tez əlavələr olan digər dinamik dəstlər üçün istifadəsi. Bu hallarda qeydlərin atlanması və dublikatları istifadəçi təcrübəsini pisləşdirir və müştəri tərəfində əlavə deduplikasiya məntiqi tələb edir.
Hibrid paginasiya offset və cursor-u birləşdirir: ilk sorğu başlanğıc səhifəni göstərmək üçün offset-dən, sonrakılar isə sonsuz skroll yükləmək üçün cursor-dan istifadə edir. Bu yanaşma Instagram və Twitter-də tətbiq edilmişdir, burada ilk səhifə cursor vasitəsilə yüklənir, lakin offset əvvəlki baxışa qayıdarkən mövqeyi hesablamaq üçün istifadə olunur.
Hibrid yanaşmanın tətbiqi müştəri tərəfində istifadəçinin virtual mövqeyinin saxlanmasını və serverdə iki paginasiya mexanizminin əlaqələndirilməsini tələb edir. Instagram Engineering bloquna görə, onların komandası ilkin yükləmə üçün offset-i əvəz edən əlavə startCursor sahəsi ilə cursor-based paginasiyadan istifadə edir.
Mobil tətbiqlər Offset Pagination-ı Android-də Retrofit/OkHttp və iOS-da URLSession/Combine ilə birlikdə istifadə edir. Tipik nümunə — RecyclerView.OnScrollListener və ya UICollectionView prefetching vasitəsilə siyahının sonuna skroll edərkən növbəti səhifənin yüklənməsidir.
Mobil müştəridə offset-paginasiyanın tətbiqi üç komponenti əhatə edir: paginasiya meneceri (cari offset və hasMore saxlayır), siyahı adapteri (elementləri və yükləmə göstəricisini göstərir) və depozitoriya (sorğuları icra edir və xətaları idarə edir). Android Jetpack həm offset, həm də cursor-based paginasiyanı qutudan çıxan kimi dəstəkləyən Paging 3 Kitabxanasını təklif edir.
Paging 3 — məlumatların səhifələrlə yüklənməsi üçün Android Jetpack kitabxanası. O, offset izləmə, yükləmə vəziyyətinin idarə edilməsi və skroll zamanı avtomatik yükləmə daxil olmaqla paginasiya məntiqini inkapsulyasiya edir. PagingSource növbəti və əvvəlki səhifələr üçün açarları müəyyən edir.
class OffsetPagingSource(
private val api: ApiService,
private val limit: Int = 20
) : PagingSource<Int, Item>() {
override suspend fun load(
params: LoadParams<Int>
): LoadResult<Int, Item> {
val offset = params.key ?: 0
return try {
val response = api.getItems(offset, limit)
LoadResult.Page(
data = response.items,
prevKey = null,
nextKey = if (response.hasMore) offset + limit else null
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
}
PagingSource səhifələr üzrə naviqasiya üçün prevKey və nextKey açarlarını müəyyən edir. Offset-paginasiyada prevKey həmişə null-dur (tarixçə saxlanılmadan əvvəlki səhifəyə keçmək mümkün deyil), nextKey isə server hasMore = false qaytarana qədər hər yükləmədə limit qədər artır. Bu, mobil siyahılar üçün sadə və proqnozlaşdırıla bilən modeldir.
Birinci səhv — sıralama olmadan qeydlərin sırasına güvənmək. Offset Pagination tələb edir unikal sahə üzrə sabit ORDER BY sıralaması. Olmadan DBMS qeydləri ixtiyari qaydada qaytara bilər ki, bu da səhifələr arasında təsadüfi dublikatlara və atlamalara səbəb olur.
İkinci səhv — UI-da səhifə nömrəsini hesablamaq üçün offset-dən istifadə etmək. page = offset / limit + 1 düsturu yalnız heç bir qeydin silinmədiyi və ya yükləmələr arasında əlavə edilmədiyi şərti ilə işləyir. Dinamik məlumatlarda səhifə nömrəsi qeyri-dəqiq olur və istifadəçi yanlış məlumat görür.
Üçüncü səhv — böyük offset ilə sorğuların vaxt limitlərini nəzərə almamaq. Offset 100000-dən yuxarı olduqda sorğu onlarla saniyə çəkə bilər, UI-nı bloklayır və server resurslarını istehlak edir. API səviyyəsində maksimum offset dəyəri (məsələn, 10000) təyin etmək və böyük həcmlər üçün cursor-based paginasiyadan istifadə etmək tövsiyə olunur.
Dördüncü səhv — cavaba total count əlavə etməmək. Ümumi qeyd sayı olmadan müştəri səhifələrin sayını göstərə və nömrələrlə paginasiyanı tətbiq edə bilməz. Lakin böyük cədvəllərdə COUNT(*) hesablanması da bahalıdır — 100000 qeyddən yuxarı dəstlər üçün təxmini qiymətləndirmələrdən istifadə edin və ya maksimum total dəyərini məhdudlaşdırın.
Tez-tez verilən suallar
Offset qeydləri atlamaq üçün rəqəmsal yerdəyişmədən (offset) istifadə edir, cursor isə əvvəlki səhifənin son qeydinə işarəçidən. Offset tətbiqdə daha sadədir, lakin əlavələr zamanı dublikatlardan və böyük yerdəyişmələrdə performans itkisindən əziyyət çəkir. Cursor məlumatlardakı istənilən dəyişiklikdə sabitdir.
Offset paginasiya cədvəlin tam skan edilməsi səbəbindən 10000 qeyddən yuxarı offset-də səmərəsizdir. O, həmçinin sorğular arasında yeni qeydlərin göründüyü dinamik dəstlər (feed-lər, çatlar) üçün yararsızdır — istifadəçi naviqasiya zamanı atlamalar və dublikatlar görür.
Optimal limit qeydin ölçüsündən və şəbəkə sürətindən asılıdır — səhifə başına 10-dan 50-yə qədər. Böyük şəkilləri olan siyahılar üçün limit = 10-15, mətn məlumatları üçün — 20-50 istifadə edin. Həmişə müştəriyə serverdə maksimum məhdudiyyətlə (adətən 100) öz limitini təyin etməyə icazə verin.
Dublikatlarla mübarizə üçün unikal ID üzrə müştəri tərəfində deduplikasiyadan istifadə edin, unikal sahə üzrə stabil sıralama tətbiq edin və ya cursor-based paginasiyaya keçin. Android Paging 3 siyahı elementlərinin avtomatik deduplikasiyası üçün açarı dəstəkləyir.
Bəli, GraphQL sorğuda offset və limit arqumentləri vasitəsilə offset-paginasiyanı dəstəkləyir, baxmayaraq ki, Relay spesifikasiyası cursor-based yanaşmanı tövsiyə edir. Apollo GraphQL və Relay kitabxanaları səhifələrin vəziyyətinin avtomatik idarə edilməsi ilə offset-paginasiyanın daxili dəstəyini təklif edir.
Xülasə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun