Offset Pagination — ऑफ़सेट के साथ पेजिनेशन — HTTP API के माध्यम से डेटा को पृष्ठानुसार लोड करने की एक विधि। क्लाइंट offset (शुरुआत से ऑफ़सेट) और limit (पृष्ठ आकार) पैरामीटर भेजता है, और सर्वर offset स्थिति से रिकॉर्ड लौटाता है। REST API Tutorial के अनुसार, यह दृष्टिकोण कार्यान्वयन की सरलता के कारण RESTful सेवाओं में व्यापक रूप से उपयोग किया जाता है। हालांकि, बड़े डेटा वॉल्यूम पर, ऑफ़सेट-पेजिनेशन आवश्यक स्थिति तक पूर्ण तालिका स्कैनिंग के कारण प्रदर्शन खो देता है।
मुख्य बिंदु
Offset Pagination डेटा को पृष्ठानुसार विभाजित करने की एक विधि है जिसमें क्लाइंट अनुरोध में दो पैरामीटर होते हैं: offset (कितने रिकॉर्ड छोड़ने हैं) और limit (कितने रिकॉर्ड लौटाने हैं)। सर्वर OFFSET और LIMIT के साथ SQL क्वेरी निष्पादित करता है, निर्दिष्ट संख्या में पंक्तियों को छोड़ता है और एक निश्चित आकार का परिणाम सेट लौटाता है।
यह विधि रिलेशनल डेटाबेस में पृष्ठ नेविगेशन को व्यवस्थित करने के सबसे सरल तरीके के रूप में उत्पन्न हुई और REST आर्किटेक्चर के विकास के साथ HTTP API में स्थानांतरित हो गई। Offset Pagination को सर्वर पर स्थिति संग्रहीत करने की आवश्यकता नहीं है — प्रत्येक अनुरोध स्वतंत्र है और इसमें क्वेरी के लिए सभी आवश्यक जानकारी होती है।
Postman (2025) के API डिज़ाइन अध्ययन के अनुसार, ऑफ़सेट पेजिनेशन का उपयोग 72% सार्वजनिक REST API में किया जाता है, जो बड़े डेटा सेट पर ज्ञात प्रदर्शन सीमाओं के बावजूद इसे प्रमुख मानक बनाता है।
Offset Pagination के साथ एक विशिष्ट REST अनुरोध में क्वेरी पैरामीटर offset और limit शामिल होते हैं। प्रतिक्रिया में अनुरोधित पृष्ठ की रिकॉर्ड सूची और नेविगेशन इंटरफ़ेस बनाने के लिए मेटाडेटा होता है।
Limit पैरामीटर लौटाए गए रिकॉर्ड की संख्या को प्रतिबंधित करता है और सर्वर व क्लाइंट को अत्यधिक लोड से बचाता है। डेटा जटिलता के आधार पर limit के विशिष्ट मान 10 से 50 रिकॉर्ड प्रति पृष्ठ होते हैं।
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 और FETCH NEXT (या MySQL/SQLite में LIMIT) निर्माणों के साथ SQL क्वेरी में परिवर्तित होता है। डेटाबेस सर्वर तालिका को स्कैन करता है, ऑफ़सेट के बराबर पंक्तियों को छोड़ता है और अगली limit पंक्तियों को लौटाता है। ऑफ़सेट जितना बड़ा होगा, क्वेरी उतनी ही धीमी होगी।
प्रदर्शन समस्या इस तथ्य से संबंधित है कि डेटाबेस सीधे ऑफ़सेट स्थिति पर नहीं जा सकता — उसे सभी पिछली पंक्तियों को पढ़ना और त्यागना होगा। offset = 100000 और limit = 20 पर, DBMS 100,020 पंक्तियाँ पढ़ता है और केवल 20 लौटाता है।
SQL — वह भाषा जिसमें सर्वर ऑफ़सेट पेजिनेशन निष्पादित करता है। PostgreSQL और MySQL LIMIT का उपयोग करते हैं, जबकि SQL Server और Oracle OFFSET...FETCH का उपयोग करते हैं। विभिन्न DBMS इस क्वेरी को अलग-अलग तरीके से अनुकूलित करते हैं, लेकिन मूल स्कैनिंग समस्या वही रहती है।
SELECT id, title, created_at
FROM articles
ORDER BY created_at DESC
OFFSET 100000 ROWS
FETCH NEXT 20 ROWS ONLY;
डेटा संगति गतिशील सेट के साथ काम करते समय Offset Pagination का मुख्य दोष है। यदि दो उपयोगकर्ता अनुरोधों के बीच तालिका की शुरुआत में एक नया रिकॉर्ड जोड़ा जाता है, तो सभी मौजूदा रिकॉर्ड स्थानांतरित हो जाते हैं। उपयोगकर्ता डुप्लिकेट या अंतराल देखता है।
मान लीजिए limit = 20 के साथ 100 रिकॉर्ड की तालिका है। पृष्ठ 1 पर, उपयोगकर्ता रिकॉर्ड 1-20 देखता है। एक प्रशासक 5 नए रिकॉर्ड जोड़ता है। पृष्ठ 2 पर, उपयोगकर्ता अपेक्षित 21-40 के बजाय रिकॉर्ड 26-45 देखता है — रिकॉर्ड 21-25 छूट गए, और पिछले सेट के रिकॉर्ड 21-25 पृष्ठ 1 पर डुप्लिकेट हो गए।
Cursor-based पेजिनेशन Offset Pagination का एक विकल्प है जो वर्तमान पृष्ठ के अंतिम रिकॉर्ड पर पॉइंटर का उपयोग करता है। संख्यात्मक ऑफ़सेट के बजाय, क्लाइंट अंतिम प्राप्त रिकॉर्ड का पहचानकर्ता भेजता है, और सर्वर उसके बाद अगले N रिकॉर्ड लौटाता है।
Cursor-based दृष्टिकोण संगति समस्या को हल करता है: कर्सर की स्थिति इन्सर्ट या डिलीट करने पर नहीं बदलती क्योंकि कर्सर एक स्थिति के बजाय एक विशिष्ट रिकॉर्ड को संदर्भित करता है। हालांकि, यह कार्यान्वयन में अधिक जटिल है — इसके लिए एक अद्वितीय सॉर्ट करने योग्य फ़ील्ड (आमतौर पर ID या timestamp) की आवश्यकता होती है।
| पैरामीटर | Offset Pagination | Cursor-based Pagination |
|---|---|---|
| सरलता | उच्च — दो संख्यात्मक पैरामीटर | मध्यम — कर्सर एन्कोडिंग आवश्यक |
| संगति | निम्न — इन्सर्ट पर डुप्लिकेट | उच्च — कर्सर परिवर्तनों से अप्रभावित |
| प्रदर्शन | बड़े ऑफ़सेट पर घटता है | किसी भी मात्रा पर स्थिर |
| पृष्ठ पर कूदना | हाँ — किसी भी पृष्ठ पर जा सकते हैं | नहीं — केवल अनुक्रमिक नेविगेशन |
| इसके लिए उपयुक्त | <10K रिकॉर्ड की तालिकाएँ, पृष्ठ संख्या वाली UI | फ़ीड, अनंत स्क्रॉल, बड़े सेट |
दृष्टिकोणों के बीच चुनाव उपयोगकर्ता इंटरफ़ेस आवश्यकताओं पर निर्भर करता है। यदि पृष्ठ संख्याओं और सीधे कूदने वाले नेविगेशन की आवश्यकता है — Offset Pagination सरल है। अनंत स्क्रॉल या समाचार फ़ीड के लिए, कर्सर बेहतर हैं।
Keyset पेजिनेशन cursor-based दृष्टिकोण का एक प्रकार है जिसमें OFFSET के बजाय WHERE का उपयोग करके अद्वितीय कुंजी पर फ़िल्टरिंग की जाती है। SQL क्वेरी WHERE id > lastId जैसी शर्त का उपयोग करती है, जो डेटाबेस को त्यागी गई पंक्तियों को स्कैन किए बिना इंडेक्स का उपयोग करने की अनुमति देती है।
PostgreSQL Wiki के अनुसार, keyset पेजिनेशन बड़े ऑफ़सेट पर ऑफ़सेट क्वेरी से 100-1000 गुना तेज़ चलता है क्योंकि इंडेक्स स्कैन पूर्ण तालिका स्कैन को बदल देता है। नुकसान अनुक्रमिक पार किए बिना किसी भी पृष्ठ पर कूदने में असमर्थता है।
Offset Pagination छोटे से मध्यम डेटा सेट (10,000 रिकॉर्ड तक) के लिए इष्टतम है जहाँ उपयोगकर्ता को पृष्ठ संख्या इंटरफ़ेस की आवश्यकता होती है। विशिष्ट परिदृश्यों में एडमिन पैनल, ऑर्डर सूचियाँ और पृष्ठ-आधारित पेजिनेशन वाले फ़िल्टर किए गए कैटलॉग शामिल हैं।
मोबाइल ऐप्लिकेशन के लिए, ऑफ़सेट पेजिनेशन ऐतिहासिक डेटा लोड करने के लिए उपयुक्त है जहाँ नए इन्सर्ट दुर्लभ या असंभव हैं — उदाहरण के लिए, उपयोगकर्ता ऑर्डर इतिहास, पूर्ण कार्य सूचियाँ, या लेन-देन संग्रह। इन परिदृश्यों में, संगति समस्या उत्पन्न नहीं होती।
अनुशंसित नहीं सोशल मीडिया फ़ीड, टिप्पणी सूचियाँ, चैट और बार-बार इन्सर्ट वाले अन्य गतिशील सेट के लिए। इन मामलों में, अंतराल और डुप्लिकेट रिकॉर्ड उपयोगकर्ता अनुभव को खराब करते हैं और क्लाइंट पर अतिरिक्त डिडुप्लिकेशन लॉजिक की आवश्यकता होती है।
हाइब्रिड पेजिनेशन offset और cursor को जोड़ता है: पहला अनुरोध प्रारंभिक पृष्ठ दिखाने के लिए offset का उपयोग करता है, जबकि बाद के अनुरोध अनंत स्क्रॉल लोडिंग के लिए cursor का उपयोग करते हैं। यह दृष्टिकोण Instagram और Twitter में उपयोग किया जाता है, जहाँ पहला पृष्ठ cursor के माध्यम से लोड होता है, लेकिन पिछले दृश्य पर लौटने पर स्थिति की गणना के लिए offset का उपयोग किया जाता है।
हाइब्रिड दृष्टिकोण को लागू करने के लिए क्लाइंट पर उपयोगकर्ता की आभासी स्थिति संग्रहीत करने और सर्वर पर दो पेजिनेशन तंत्रों के समन्वय की आवश्यकता होती है। Instagram Engineering ब्लॉग के अनुसार, उनकी टीम प्रारंभिक लोडिंग के लिए offset को बदलने वाले अतिरिक्त startCursor फ़ील्ड के साथ cursor-based पेजिनेशन का उपयोग करती है।
मोबाइल ऐप्लिकेशन Android पर Retrofit/OkHttp और iOS पर URLSession/Combine के साथ Offset Pagination का उपयोग करते हैं। विशिष्ट पैटर्न RecyclerView.OnScrollListener या UICollectionView prefetching के माध्यम से सूची के अंत तक स्क्रॉल करने पर अगला पृष्ठ लोड करना है।
मोबाइल क्लाइंट पर ऑफ़सेट पेजिनेशन लागू करने में तीन घटक शामिल हैं: एक पेजिनेशन मैनेजर (वर्तमान offset और hasMore संग्रहीत करता है), एक सूची एडाप्टर (आइटम और लोडिंग संकेतक प्रदर्शित करता है), और एक रिपॉज़िटरी (अनुरोध निष्पादित करता है और त्रुटियाँ संभालता है)। Android Jetpack Paging 3 लाइब्रेरी प्रदान करता है, जो बॉक्स से बाहर offset और cursor-based दोनों पेजिनेशन का समर्थन करती है।
Paging 3 पृष्ठानुसार डेटा लोड करने के लिए Android Jetpack लाइब्रेरी है। यह ऑफ़सेट ट्रैकिंग, लोडिंग स्थिति प्रबंधन और स्क्रॉल पर स्वचालित प्रीफ़ेचिंग सहित पेजिनेशन लॉजिक को समाहित करती है। PagingSource अगले और पिछले पृष्ठों के लिए कुंजियाँ परिभाषित करता है।
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 पृष्ठ नेविगेशन के लिए prevKey और nextKey कुंजियाँ परिभाषित करता है। ऑफ़सेट पेजिनेशन के साथ, prevKey हमेशा null होता है (इतिहास सहेजे बिना पिछले पृष्ठ पर नहीं जा सकते), जबकि nextKey प्रत्येक लोड के साथ limit से बढ़ता है जब तक सर्वर hasMore = false नहीं लौटाता। यह मोबाइल सूचियों के लिए एक सरल और पूर्वानुमानित मॉडल है।
पहली गलती — बिना सॉर्टिंग के रिकॉर्ड क्रम पर निर्भर रहना। Offset Pagination आवश्यकता है एक अद्वितीय फ़ील्ड पर स्थिर ORDER BY सॉर्टिंग की। इसके बिना, DBMS मनमाने क्रम में रिकॉर्ड लौटा सकता है, जिससे पृष्ठों के बीच यादृच्छिक डुप्लिकेट और अंतराल होते हैं।
दूसरी गलती — UI में पृष्ठ संख्या की गणना के लिए offset का उपयोग करना। सूत्र page = offset / limit + 1 केवल तभी काम करता है जब लोड के बीच कोई रिकॉर्ड हटाया या जोड़ा न गया हो। गतिशील डेटा के साथ, पृष्ठ संख्या गलत हो जाती है और उपयोगकर्ता गलत जानकारी देखता है।
तीसरी गलती — बड़े offset वाली क्वेरी के टाइमआउट को अनदेखा करना। 100,000 से अधिक offset पर, क्वेरी दसियों सेकंड ले सकती है, UI को अवरुद्ध कर सकती है और सर्वर संसाधनों का उपभोग कर सकती है। API स्तर पर अधिकतम offset मान (जैसे, 10,000) सेट करने और बड़े वॉल्यूम के लिए cursor-based पेजिनेशन का उपयोग करने की अनुशंसा की जाती है।
चौथी गलती — प्रतिक्रिया में total count शामिल न करना। रिकॉर्ड की कुल संख्या के बिना, क्लाइंट पृष्ठ संख्या प्रदर्शित नहीं कर सकता और क्रमांकित पेजिनेशन लागू नहीं कर सकता। हालांकि, बड़ी तालिकाओं पर COUNT(*) महंगा है — 100,000 रिकॉर्ड से अधिक सेट के लिए, अनुमानित अनुमानों का उपयोग करें या अधिकतम कुल मान सीमित करें।
अक्सर पूछे जाने वाले प्रश्न
Offset रिकॉर्ड छोड़ने के लिए संख्यात्मक ऑफ़सेट का उपयोग करता है, जबकि cursor पिछले पृष्ठ के अंतिम रिकॉर्ड पर पॉइंटर का उपयोग करता है। Offset लागू करना सरल है लेकिन इन्सर्ट पर डुप्लिकेट और बड़े ऑफ़सेट पर प्रदर्शन हानि से ग्रस्त है। Cursor डेटा में किसी भी बदलाव पर स्थिर रहता है।
ऑफ़सेट पेजिनेशन 10,000 रिकॉर्ड से अधिक ऑफ़सेट पर पूर्ण तालिका स्कैनिंग के कारण अकुशल है। यह गतिशील सेट (फ़ीड, चैट) के लिए भी अनुपयुक्त है जहाँ अनुरोधों के बीच नए रिकॉर्ड दिखाई देते हैं — उपयोगकर्ता नेविगेशन के दौरान अंतराल और डुप्लिकेट रिकॉर्ड देखता है।
इष्टतम limit रिकॉर्ड आकार और नेटवर्क गति पर निर्भर करता है — 10 से 50 आइटम प्रति पृष्ठ। बड़ी छवियों वाली सूचियों के लिए, limit = 10-15 का उपयोग करें; टेक्स्ट डेटा के लिए, 20-50। हमेशा क्लाइंट को सर्वर पर अधिकतम सीमा (आमतौर पर 100) के साथ अपना limit निर्दिष्ट करने दें।
डुप्लिकेट से निपटने के लिए, अद्वितीय ID द्वारा क्लाइंट-साइड डिडुप्लिकेशन का उपयोग करें, अद्वितीय फ़ील्ड पर स्थिर सॉर्टिंग लागू करें, या cursor-based पेजिनेशन पर स्विच करें। Android Paging 3 सूची आइटम के स्वचालित डिडुप्लिकेशन के लिए key का समर्थन करता है।
हाँ, GraphQL क्वेरी में offset और limit तर्कों के माध्यम से ऑफ़सेट पेजिनेशन का समर्थन करता है, हालाँकि Relay विनिर्देश cursor-based दृष्टिकोण की अनुशंसा करता है। Apollo GraphQL और Relay लाइब्रेरीज़ स्वचालित पृष्ठ स्थिति प्रबंधन के साथ ऑफ़सेट पेजिनेशन के लिए अंतर्निहित समर्थन प्रदान करती हैं।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें