पेजिनेशन सूचियाँ लौटाने वाले किसी भी एपीआई के लिए आवश्यक है – इसके बिना, लाखों पंक्तियों को लौटाने वाली क्वेरी आपके सर्वर को क्रैश कर देती है और ग्राहकों को प्रभावित करती है। लेकिन बहुत भिन्न प्रदर्शन विशेषताओं वाली कई पृष्ठांकन रणनीतियाँ हैं। यह मार्गदर्शिका उन सभी को कवर करती है और प्रत्येक का उपयोग कब करना है।
📋 Table of Contents
- पेजिनेशन क्यों मायने रखता है
- रणनीति 1: ऑफसेट/लिमिट पेजिनेशन (सरल)
- रणनीति 2: कर्सर पेजिनेशन (स्केलेबल)
- रणनीति 3: कीसेट पेजिनेशन (सर्वोत्तम प्रदर्शन)
- तुलना: किसका उपयोग करें
- प्रदर्शन युक्तियाँ
- अपने सॉर्ट कॉलम को अनुक्रमित करें:
- प्रश्न: ऑफसेट या कर्सर पेजिनेशन?
- किसी भी सूची-वापसी एपीआई के लिए उचित पृष्ठांकन आवश्यक है।
पेजिनेशन क्यों मायने रखता है
- प्रदर्शन: सभी पंक्तियों को लौटाना धीमा और स्मृति-गहन है
- बैंडविड्थ: ग्राहकों को एक साथ हजारों रिकॉर्ड की आवश्यकता नहीं है
- डेटाबेस लोड: बाउंडेड क्वेरीज़ आपके डेटाबेस की सुरक्षा करती हैं
- उपयोगकर्ता अनुभव: पेजों में डेटा लोड करना तेज़ और साफ़ है
रणनीति 1: ऑफसेट/लिमिट पेजिनेशन (सरल)
-- The classic approach: OFFSET and LIMIT
SELECT * FROM products
ORDER BY created_at DESC
LIMIT 20 OFFSET 40; -- page 3 (skip 40, take 20)
// Express endpoint
app.get('/products', async (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 20;
const offset = (page - 1) * limit;
const products = await db.query(
'SELECT * FROM products ORDER BY created_at DESC LIMIT $1 OFFSET $2',
[limit, offset]
);
const total = await db.query('SELECT COUNT(*) FROM products');
res.json({
data: products.rows,
pagination: {
page,
limit,
total: total.rows[0].count,
totalPages: Math.ceil(total.rows[0].count / limit),
}
});
});
पेशेवर: सरल, किसी भी पृष्ठ पर जाने का समर्थन करता है, कुल संख्या दिखाता है।
विपक्ष: बड़े ऑफसेट पर धीमा (डेटाबेस अभी भी सभी छोड़ी गई पंक्तियों को स्कैन करता है), और यदि अनुरोधों के बीच डेटा बदलता है तो परिणाम बदल सकते हैं।
रणनीति 2: कर्सर पेजिनेशन (स्केलेबल)
ऑफ़सेट के बजाय, अगला पृष्ठ लाने के लिए “कर्सर” (आमतौर पर अंतिम आइटम की आईडी या टाइमस्टैम्प) का उपयोग करें। यह लाखों पंक्तियों तक पहुंच जाता है क्योंकि डेटाबेस सीधे स्थिति पर पहुंच जाता है:
-- Fetch items AFTER a cursor (much faster than large OFFSET)
SELECT * FROM products
WHERE created_at < $1 -- cursor = last item's created_at
ORDER BY created_at DESC
LIMIT 20;
app.get('/products', async (req, res) => {
const limit = parseInt(req.query.limit) || 20;
const cursor = req.query.cursor; // the last item's timestamp/id
let query, params;
if (cursor) {
query = 'SELECT * FROM products WHERE created_at < $1 ORDER BY created_at DESC LIMIT $2';
params = [cursor, limit + 1]; // fetch one extra to check for more
} else {
query = 'SELECT * FROM products ORDER BY created_at DESC LIMIT $1';
params = [limit + 1];
}
const result = await db.query(query, params);
const hasMore = result.rows.length > limit;
const items = hasMore ? result.rows.slice(0, limit) : result.rows;
const nextCursor = hasMore ? items[items.length - 1].created_at : null;
res.json({
data: items,
pagination: { nextCursor, hasMore }
});
});
पेशेवर: किसी भी पैमाने पर तेज़ (कोई ऑफसेट स्कैनिंग नहीं), डेटा बदलने पर भी स्थिर परिणाम।
विपक्ष: मनमाने पेजों पर नहीं जा सकते, कुल पेज गिनती नहीं, थोड़ा अधिक जटिल।
रणनीति 3: कीसेट पेजिनेशन (सर्वोत्तम प्रदर्शन)
-- Keyset uses a unique, ordered column (often id) for precise positioning
SELECT * FROM products
WHERE (created_at, id) < ($1, $2) -- composite cursor handles ties
ORDER BY created_at DESC, id DESC
LIMIT 20;
समान टाइमस्टैम्प वाली पंक्तियों को संभालने के लिए कीसेट पेजिनेशन एक समग्र कर्सर (जैसे create_at + id) का उपयोग करता है। यह सबसे मजबूत उच्च-प्रदर्शन दृष्टिकोण है, जिसका उपयोग विशाल डेटासेट की सेवा देने वाले एपीआई द्वारा किया जाता है।
तुलना: किसका उपयोग करें
| रणनीति | के लिए सर्वश्रेष्ठ स्केल | ऑफसेट/सीमा |
|---|---|---|
| छोटे डेटासेट, व्यवस्थापक यूआई को पृष्ठ संख्या की आवश्यकता होती है | लघु-मध्यम | कर्सर |
| फ़ीड, अनंत स्क्रॉल, बड़े डेटासेट | बड़ा | कीसेट |
| विशाल डेटासेट, उच्च-प्रदर्शन आवश्यकताएँ | बहुत बड़ा | लगातार प्रतिक्रिया प्रारूप |
प्रदर्शन युक्तियाँ
// Offset-based response
{
"data": [ /* items */ ],
"pagination": {
"page": 3,
"limit": 20,
"total": 1543,
"totalPages": 78
}
}
// Cursor-based response
{
"data": [ /* items */ ],
"pagination": {
"nextCursor": "2026-07-20T10:30:00Z",
"hasMore": true
}
}
अपने सॉर्ट कॉलम को अनुक्रमित करें:
- पेजिनेशन क्वेरीज़ को ORDER BY कॉलम पर एक इंडेक्स की आवश्यकता होती है, या वे धीमे हैंविशाल तालिकाओं पर COUNT(*) से बचें:
- सभी पंक्तियों को गिनना महंगा है – कर्सर पृष्ठांकन कुल गिनती की आवश्यकता से बचाता हैसीमा कैप करें:
- अधिकतम पृष्ठ आकार लागू करें (उदाहरण के लिए, 100) ताकि ग्राहक हर चीज़ का अनुरोध न कर सकेंबड़े डेटा के लिए कर्सर/कीसेट का उपयोग करें:
- बड़े ऑफसेट पर ऑफसेट पेजिनेशन बुरी तरह खराब हो जाता है – डेटाबेस सभी छोड़ी गई पंक्तियों को स्कैन करता है“अधिक है” का पता लगाने के लिए सीमा+1 प्राप्त करें:
- यह जानने के लिए एक अतिरिक्त पंक्ति का अनुरोध करें कि क्या कोई अगला पृष्ठ बिना अलग गिनती के हैअक्सर पूछे जाने वाले प्रश्न
प्रश्न: ऑफसेट या कर्सर पेजिनेशन?
ए: छोटे डेटासेट और एडमिन यूआई के लिए ऑफसेट, जिन्हें पेज नंबर और विशिष्ट पेजों पर जाने की आवश्यकता होती है। फ़ीड, अनंत स्क्रॉल और बड़े डेटासेट के लिए कर्सर जहां प्रदर्शन और स्थिरता मायने रखती है। कर्सर कहीं बेहतर तरीके से स्केल करता है लेकिन मनमाने पेजों पर नहीं जा सकता।
प्रश्न: मेरा ऑफसेट पेजिनेशन धीमा क्यों है?
आपके पृष्ठ पर लौटने से पहले डेटाबेस को स्कैन करता है और 100,000 पंक्तियों को हटा देता है – जैसे-जैसे ऑफ़सेट बढ़ता है, धीमा होता जाता है। कर्सर या कीसेट पेजिनेशन पर स्विच करें, जो अनुक्रमित कॉलम का उपयोग करके सीधे स्थिति पर पहुंच जाता है।
A: OFFSET 100000प्रश्न: मैं पृष्ठों के बीच डेटा परिवर्तन को कैसे संभालूं?
उ: यदि अनुरोधों के बीच पंक्तियाँ जोड़ी/हटाई जाती हैं तो ऑफसेट पेजिनेशन आइटम को छोड़ या डुप्लिकेट कर सकता है। कर्सर पेजिनेशन स्थिर है क्योंकि यह एक विशिष्ट आइटम की स्थिति पर निर्भर करता है, संख्यात्मक ऑफसेट पर नहीं। जब डेटा बार-बार बदलता है तो कर्सर पेजिनेशन का उपयोग करें।
प्रश्न: क्या मुझे कुल गिनती वापस करने की आवश्यकता है?
उ: पेज नंबरों के साथ ऑफसेट पेजिनेशन के लिए, आमतौर पर हाँ। लेकिन बड़ी टेबलों पर COUNT(*) महंगा है। कर्सर पेजिनेशन इसे पूरी तरह से टाल देता है (सिर्फ “हैज़मोर”)। यदि आपको विशाल तालिकाओं पर अनुमानित गणना की आवश्यकता है, तो कैश्ड या अनुमानित गणना पर विचार करें।
प्रश्न: एक अच्छा डिफ़ॉल्ट और अधिकतम पृष्ठ आकार क्या है?
ए: 20-25 डिफ़ॉल्ट के रूप में, अधिकतम 100 लागू सर्वर-साइड के साथ। यह प्रतिक्रिया आकार और अनुरोधों की संख्या को संतुलित करता है। हमेशा सीमा तय करें ताकि ग्राहक
के साथ असीमित डेटा का अनुरोध न कर सकें निष्कर्ष?limit=999999.
किसी भी सूची-वापसी एपीआई के लिए उचित पृष्ठांकन आवश्यक है।
का प्रयोग करें छोटे डेटासेट और व्यवस्थापक यूआई के लिए ऑफसेट/सीमा, पेज नंबर की आवश्यकता होती है, फ़ीड और बड़े डेटासेट के लिए कर्सर पेजिनेशन, और बड़े पैमाने पर उच्च-प्रदर्शन आवश्यकताओं के लिए कीसेट पेजिनेशनका प्रयोग करें छोटे डेटासेट और व्यवस्थापक यूआई के लिए ऑफसेट/सीमा, पेज नंबर की आवश्यकता होती है, फ़ीड और बड़े डेटासेट के लिए कर्सर पेजिनेशन, और बड़े पैमाने पर उच्च-प्रदर्शन आवश्यकताओं के लिए कीसेट पेजिनेशन. ऑफसेट सबसे सरल है लेकिन बड़े ऑफसेट पर ख़राब हो जाता है; अनुक्रमित कॉलम का उपयोग करके सीधे स्थिति पर जाकर कर्सर और कीसेट को लाखों पंक्तियों तक स्केल करें। अपने सॉर्ट कॉलम को अनुक्रमित करें, पृष्ठ आकार को सीमित करें, अधिक पृष्ठों का पता लगाने के लिए सीमा+1 प्राप्त करें, और एक सुसंगत प्रतिक्रिया प्रारूप लौटाएं। अपने डेटा पैमाने के लिए सही रणनीति चुनने से आपका एपीआई तेज़ रहता है और आपका डेटा बढ़ने पर आपका डेटाबेस स्वस्थ रहता है।
🔗 Share this article
✍️ Leave a Comment