Offset Pagination στην ανάπτυξη εφαρμογών για κινητά: τι είναι και πώς να το εφαρμόσετε

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-03-11 Χρόνος ανάγνωσης: 10 λεπ

Offset Pagination — σελιδοποίηση με μετατόπιση — μέθοδος φόρτωσης δεδομένων ανά σελίδα μέσω HTTP API. Ο πελάτης μεταδίδει τις παραμέτρους offset (μετατόπιση από την αρχή) και limit (μέγεθος σελίδας), και ο διακομιστής επιστρέφει εγγραφές από τη θέση offset. Σύμφωνα με το REST API Tutorial, αυτή η προσέγγιση χρησιμοποιείται ευρέως σε υπηρεσίες RESTful λόγω της απλότητας υλοποίησης. Ωστόσο, σε μεγάλους όγκους δεδομένων, η σελιδοποίηση με offset χάνει απόδοση λόγω της πλήρους σάρωσης του πίνακα μέχρι την απαιτούμενη θέση.

Βασικά σημεία

  • Offset Pagination — μέθοδος σελιδοποίησης όπου ο διακομιστής παραλείπει N εγγραφές και επιστρέφει τις επόμενες M.
  • Απλότητα υλοποίησης το καθιστά πρότυπο για REST API και κινητούς πελάτες.
  • Πρόβλημα παράλειψης — κατά την εισαγωγή εγγραφών μεταξύ αιτημάτων, ο χρήστης βλέπει διπλότυπα.
  • Άλματα στα δεδομένα — η διαγραφή εγγραφών οδηγεί σε μετατόπιση σελίδων και απώλεια περιεχομένου.
  • Cursor-based σελιδοποίηση λύνει αυτά τα προβλήματα μέσω δείκτη στην τελευταία εγγραφή αντί για μετατόπιση.

Τι είναι το Offset Pagination;

Offset Pagination — είναι μια μέθοδος διαίρεσης δεδομένων ανά σελίδα, όπου το αίτημα του πελάτη περιέχει δύο παραμέτρους: offset (πόσες εγγραφές να παραλειφθούν) και limit (πόσες εγγραφές να επιστραφούν). Ο διακομιστής εκτελεί ένα ερώτημα SQL με OFFSET και LIMIT, παραλείπει τον καθορισμένο αριθμό γραμμών και επιστρέφει το σύνολο αποτελεσμάτων σταθερού μεγέθους.

Η μέθοδος εμφανίστηκε στις σχεσιακές βάσεις δεδομένων ως ο απλούστερος τρόπος οργάνωσης πλοήγησης μεταξύ σελίδων και μεταφέρθηκε στο HTTP API με την ανάπτυξη της αρχιτεκτονικής REST. Το Offset Pagination δεν απαιτεί αποθήκευση κατάστασης στον διακομιστή — κάθε αίτημα είναι ανεξάρτητο και περιέχει όλες τις απαραίτητες πληροφορίες για την επιλογή.

Σύμφωνα με έρευνα σχεδιασμού API από την Postman (2025), η σελιδοποίηση με offset χρησιμοποιείται στο 72% των δημόσιων REST API, καθιστώντας την κυρίαρχο πρότυπο παρά τους γνωστούς περιορισμούς απόδοσης σε μεγάλους όγκους δεδομένων.

Δομή αιτήματος και απόκρισης

Ένα τυπικό αίτημα REST με Offset Pagination περιλαμβάνει τις παραμέτρους ερωτήματος offset και limit. Η απόκριση περιέχει μια λίστα εγγραφών της ζητούμενης σελίδας και μεταδεδομένα για τη δημιουργία της διεπαφής πλοήγησης.

Η παράμετρος limit περιορίζει τον αριθμό των επιστρεφόμενων εγγραφών και προστατεύει τον διακομιστή και τον πελάτη από υπερβολικό φορτίο. Τυπικές τιμές limit — από 10 έως 50 εγγραφές ανά σελίδα ανάλογα με την πολυπλοκότητα των δεδομένων.

kotlin
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 Pagination μετατρέπεται σε ερώτημα SQL με κατασκευές OFFSET και FETCH NEXT (ή LIMIT σε MySQL/SQLite). Ο διακομιστής βάσης δεδομένων σαρώνει τον πίνακα, παραλείπει τον αριθμό γραμμών ίσο με το offset και επιστρέφει τις επόμενες limit γραμμές. Όσο μεγαλύτερο είναι το offset, τόσο περισσότερο διαρκεί το ερώτημα.

Το πρόβλημα απόδοσης σχετίζεται με το γεγονός ότι η βάση δεδομένων δεν μπορεί να πάει απευθείας στη θέση offset — πρέπει να διαβάσει και να απορρίψει όλες τις προηγούμενες γραμμές. Σε offset = 100000 και limit = 20, το DBMS θα διαβάσει 100020 γραμμές και θα επιστρέψει μόνο 20.

Το ερώτημα SQL κάτω από το καπό

SQL — η γλώσσα στην οποία ο διακομιστής εκτελεί τη σελιδοποίηση με offset. Σε PostgreSQL και MySQL χρησιμοποιείται LIMIT, σε SQL Server και Oracle — OFFSET...FETCH. Διαφορετικά DBMS βελτιστοποιούν αυτό το ερώτημα με τον δικό τους τρόπο, αλλά το θεμελιώδες πρόβλημα σάρωσης παραμένει το ίδιο.

sql
SELECT id, title, created_at
FROM articles
ORDER BY created_at DESC
OFFSET 100000 ROWS
FETCH NEXT 20 ROWS ONLY;

Πρόβλημα συνέπειας

Συνέπεια δεδομένων — το κύριο μειονέκτημα του Offset Pagination κατά την εργασία με δυναμικά σύνολα. Εάν μεταξύ δύο αιτημάτων χρήστη προστεθεί μια νέα εγγραφή στην αρχή του πίνακα, όλες οι υπάρχουσες εγγραφές μετατοπίζονται. Ο χρήστης βλέπει διπλότυπα ή παραλείψεις.

Φανταστείτε έναν πίνακα με 100 εγγραφές με limit = 20. Στη σελίδα 1, ο χρήστης βλέπει τις εγγραφές 1-20. Ο διαχειριστής προσθέτει 5 νέες εγγραφές. Στη σελίδα 2, ο χρήστης βλέπει τις εγγραφές 26-45 αντί για τις αναμενόμενες 21-40 — οι εγγραφές 21-25 παραλείπονται και οι εγγραφές 21-25 από το προηγούμενο σύνολο διπλοτυπούνται στη σελίδα 1.

Offset vs Cursor-based: σύγκριση προσεγγίσεων

Cursor-based pagination — εναλλακτική λύση για το Offset Pagination, που χρησιμοποιεί έναν δείκτη στην τελευταία εγγραφή της τρέχουσας σελίδας. Αντί για αριθμητική μετατόπιση, ο πελάτης μεταδίδει το αναγνωριστικό της τελευταίας ληφθείσας εγγραφής και ο διακομιστής επιστρέφει τις επόμενες N εγγραφές μετά από αυτήν.

Η προσέγγιση cursor-based λύνει το πρόβλημα συνέπειας: η θέση του δρομέα δεν αλλάζει κατά την εισαγωγή ή διαγραφή, επειδή ο δρομέας αναφέρεται σε μια συγκεκριμένη εγγραφή, όχι σε μια θέση. Ωστόσο, είναι πιο περίπλοκη στην υλοποίηση — απαιτεί ένα μοναδικό ταξινομήσιμο πεδίο (συνήθως ID ή timestamp).

ΠαράμετροςOffset PaginationCursor-based Pagination
ΑπλότηταΥψηλή — δύο αριθμητικές παράμετροιΜέτρια — απαιτεί κωδικοποίηση δρομέα
ΣυνέπειαΧαμηλή — διπλότυπα κατά την εισαγωγήΥψηλή — ο δρομέας δεν εξαρτάται από αλλαγές
ΑπόδοσηΜειώνεται με την αύξηση του offsetΣταθερή σε任何 όγκο
Άλμα σε σελίδαΝαι — μπορείτε να πάτε σε οποιαδήποτε σελίδαΌχι — μόνο διαδοχική πλοήγηση
Κατάλληλο γιαΠίνακες <10K εγγραφών, UI με αριθμούς σελίδωνFeed, ατελείωτο scroll, μεγάλα σύνολα

Η επιλογή μεταξύ προσεγγίσεων εξαρτάται από τις απαιτήσεις διεπαφής χρήστη. Εάν χρειάζεται πλοήγηση με αριθμούς σελίδων και άμεσο άλμα — το Offset Pagination είναι απλούστερο. Για ατελείωτο scroll ή feed ειδήσεων, οι δρομείς είναι προτιμότεροι.

Keyset pagination

Keyset pagination — μια παραλλαγή της προσέγγισης cursor-based, όπου το φιλτράρισμα γίνεται με μοναδικό κλειδί χρησιμοποιώντας WHERE αντί για OFFSET. Το ερώτημα SQL χρησιμοποιεί τη συνθήκη WHERE id > lastId, που επιτρέπει στη βάση δεδομένων να χρησιμοποιεί ευρετήριο χωρίς σάρωση των απορριφθέντων γραμμών.

Σύμφωνα με το PostgreSQL Wiki, η keyset pagination εκτελείται 100-1000 φορές ταχύτερα από ένα ερώτημα offset σε μεγάλες μετατοπίσεις, επειδή η σάρωση ευρετηρίου αντικαθιστά την πλήρη περιήγηση του πίνακα. Μειονέκτημα — αδυναμία άλματος σε αυθαίρετη σελίδα χωρίς διαδοχική διέλευση.

Πότε να χρησιμοποιείτε το Offset Pagination

Offset Pagination είναι βέλτιστο για μικρά και μεσαία σύνολα δεδομένων (έως 10000 εγγραφές), όπου ο χρήστης χρειάζεται μια διεπαφή με αριθμούς σελίδων. Τυπικά σενάρια — πίνακες διαχείρισης, λίστες παραγγελιών, κατάλογοι με φιλτράρισμα και σελιδοποίηση ανά σελίδα.

Για εφαρμογές κινητών, η σελιδοποίηση με offset είναι κατάλληλη κατά τη φόρτωση ιστορικών δεδομένων, όπου η εισαγωγή νέων εγγραφών είναι σπάνια ή αδύνατη — για παράδειγμα, ιστορικό παραγγελιών χρήστη, λίστα ολοκληρωμένων εργασιών, αρχείο συναλλαγών. Σε αυτά τα σενάρια, το πρόβλημα συνέπειας δεν εμφανίζεται.

Δεν συνιστάται η χρήση του Offset Pagination για feed κοινωνικών δικτύων, λίστες σχολίων, συνομιλίες και άλλα δυναμικά σύνολα με συχνές εισαγωγές. Σε αυτές τις περιπτώσεις, οι παραλείψεις και τα διπλότυπα εγγραφών υποβαθμίζουν την εμπειρία χρήστη και απαιτούν πρόσθετη λογική αφαιρετικοποίησης στον πελάτη.

Υβριδική προσέγγιση

Υβριδική σελιδοποίηση συνδυάζει offset και cursor: το πρώτο αίτημα χρησιμοποιεί offset για την εμφάνιση της αρχικής σελίδας και τα επόμενα χρησιμοποιούν cursor για τη φόρτωση ατελείωτου scroll. Αυτή η προσέγγιση εφαρμόζεται στο Instagram και το Twitter, όπου η πρώτη σελίδα φορτώνεται μέσω cursor, αλλά το offset χρησιμοποιείται για τον υπολογισμό της θέσης κατά την επιστροφή στην προηγούμενη προβολή.

Η υλοποίηση της υβριδικής προσέγγισης απαιτεί αποθήκευση της εικονικής θέσης του χρήστη στον πελάτη και συντονισμό δύο μηχανισμών σελιδοποίησης στον διακομιστή. Σύμφωνα με το blog Instagram Engineering, η ομάδα τους χρησιμοποιεί cursor-based σελιδοποίηση με ένα επιπλέον πεδίο startCursor, που αντικαθιστά το offset για αρχική φόρτωση.

Offset Pagination σε εφαρμογές κινητών

Εφαρμογές κινητών χρησιμοποιούν το Offset Pagination σε συνδυασμό με Retrofit/OkHttp σε Android και URLSession/Combine σε iOS. Το τυπικό μοτίβο — φόρτωση της επόμενης σελίδας κατά την κύλιση στο τέλος της λίστας μέσω RecyclerView.OnScrollListener ή UICollectionView prefetching.

Η υλοποίηση της σελιδοποίησης με offset σε κινητό πελάτη περιλαμβάνει τρία στοιχεία: διαχειριστή σελιδοποίησης (αποθηκεύει το τρέχον offset και το hasMore), προσαρμογέα λίστας (εμφανίζει στοιχεία και δείκτη φόρτωσης) και αποθετήριο (εκτελεί αιτήματα και χειρίζεται σφάλματα). Το Android Jetpack προσφέρει τη βιβλιοθήκη Paging 3, η οποία υποστηρίζει τόσο offset όσο και cursor-based σελιδοποίηση από το κουτί.

Υλοποίηση σε Kotlin με Paging 3

Paging 3 — βιβλιοθήκη Android Jetpack για φόρτωση δεδομένων ανά σελίδα. Ενσωματώνει τη λογική σελιδοποίησης, συμπεριλαμβανομένης της παρακολούθησης offset, διαχείρισης κατάστασης φόρτωσης και αυτόματης φόρτωσης κατά την κύλιση. Το PagingSource ορίζει κλειδιά για την επόμενη και προηγούμενη σελίδα.

kotlin
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 για πλοήγηση σελίδων. Στη σελιδοποίηση με offset, το prevKey είναι πάντα null (δεν μπορείτε να πάτε στην προηγούμενη σελίδα χωρίς αποθήκευση ιστορικού) και το nextKey αυξάνεται κατά limit σε κάθε φόρτωση, έως ότου ο διακομιστής επιστρέψει hasMore = false. Αυτό είναι ένα απλό και προβλέψιμο μοντέλο για κινητές λίστες.

Συνηθισμένα λάθη στο Offset Pagination

Πρώτο λάθος — βασισμός στη σειρά των εγγραφών χωρίς ταξινόμηση. Το Offset Pagination απαιτεί σταθερή ταξινόμηση ORDER BY σε ένα μοναδικό πεδίο. Χωρίς αυτήν, το DBMS μπορεί να επιστρέφει εγγραφές σε αυθαίρετη σειρά, οδηγώντας σε τυχαία διπλότυπα και παραλείψεις μεταξύ σελίδων.

Δεύτερο λάθος — χρήση του offset για υπολογισμό του αριθμού σελίδας στη διεπαφή. Ο τύπος page = offset / limit + 1 λειτουργεί μόνο υπό την προϋπόθεση ότι καμία εγγραφή δεν έχει διαγραφεί ή προστεθεί μεταξύ φορτώσεων. Σε δυναμικά δεδομένα, ο αριθμός σελίδας γίνεται ανακριβής και ο χρήστης βλέπει εσφαλμένες πληροφορίες.

Τρίτο λάθος — αγνόηση χρονικών ορίων ερωτημάτων με μεγάλο offset. Σε offset άνω των 100000, το ερώτημα μπορεί να διαρκέσει δεκάδες δευτερόλεπτα, μπλοκάροντας τη διεπαφή και καταναλώνοντας πόρους διακομιστή. Συνιστάται ο ορισμός μέγιστης τιμής offset σε επίπεδο API (π.χ. 10000) και η χρήση cursor-based σελιδοποίησης για μεγάλους όγκους.

Τέταρτο λάθος — μη προσθήκη total count στην απόκριση. Χωρίς τον συνολικό αριθμό εγγραφών, ο πελάτης δεν μπορεί να εμφανίσει τον αριθμό σελίδων και να υλοποιήσει σελιδοποίηση με αριθμούς. Ωστόσο, ο υπολογισμός COUNT(*) σε μεγάλους πίνακες είναι επίσης δαπανηρός — για σύνολα άνω των 100000 εγγραφών, χρησιμοποιήστε κατά προσέγγιση εκτιμήσεις ή περιορίστε τη μέγιστη τιμή total.

Συχνές Ερωτήσεις

Σε τι διαφέρει το Offset Pagination από το Cursor-based;

Το offset χρησιμοποιεί αριθμητική μετατόπιση (offset) για παράλειψη εγγραφών, ενώ ο δρομέας χρησιμοποιεί δείκτη στην τελευταία εγγραφή της προηγούμενης σελίδας. Το offset είναι απλούστερο στην υλοποίηση, αλλά υποφέρει από διπλότυπα κατά την εισαγωγή και απώλεια απόδοσης σε μεγάλες μετατοπίσεις. Ο δρομέας είναι σταθερός σε οποιεσδήποτε αλλαγές δεδομένων.

Πότε λειτουργεί άσχημα το Offset Pagination;

Η σελιδοποίηση με offset είναι αναποτελεσματική σε offset άνω των 10000 εγγραφών λόγω πλήρους σάρωσης του πίνακα. Επίσης, είναι ακατάλληλη για δυναμικά σύνολα (feed, συνομιλίες) όπου νέες εγγραφές εμφανίζονται μεταξύ αιτημάτων — ο χρήστης βλέπει παραλείψεις και διπλότυπα κατά την πλοήγηση.

Ποιο limit είναι βέλτιστο για το Offset Pagination;

Το βέλτιστο limit εξαρτάται από το μέγεθος εγγραφής και την ταχύτητα δικτύου — από 10 έως 50 στοιχεία ανά σελίδα. Για λίστες με μεγάλες εικόνες, χρησιμοποιήστε limit = 10-15, για δεδομένα κειμένου — 20-50. Πάντα να επιτρέπετε στον πελάτη να καθορίζει το δικό του limit με ένα μέγιστο όριο στον διακομιστή (συνήθως 100).

Πώς να αντιμετωπίσουμε τα διπλότυπα στο Offset Pagination;

Για την αντιμετώπιση διπλοτύπων, χρησιμοποιήστε αφαιρετικοποίηση στον πελάτη βάσει μοναδικού ID, εφαρμόστε σταθερή ταξινόμηση σε μοναδικό πεδίο ή μεταβείτε σε cursor-based σελιδοποίηση. Το Android Paging 3 υποστηρίζει κλειδί για αυτόματη αφαιρετικοποίηση στοιχείων λίστας.

Μπορεί να χρησιμοποιηθεί το Offset Pagination με GraphQL;

Ναι, το GraphQL υποστηρίζει σελιδοποίηση με offset μέσω των ορισμάτων offset και limit στο ερώτημα, αν και η προδιαγραφή Relay συνιστά την προσέγγιση cursor-based. Οι βιβλιοθήκες Apollo GraphQL και Relay προσφέρουν ενσωματωμένη υποστήριξη για σελιδοποίηση με offset με αυτόματη διαχείριση κατάστασης σελίδων.

Σύνοψη

  • Offset Pagination — μέθοδος σελιδοποίησης με παραμέτρους offset και limit για παράλειψη και περιορισμό εγγραφών κατά τη φόρτωση δεδομένων ανά σελίδα από API.
  • Απλότητα υλοποίησης και ανεξαρτησία αιτημάτων καθιστούν το Offset Pagination την τυπική προσέγγιση για το 72% των REST API (δεδομένα Postman, 2025).
  • Απόδοση μειώνεται σε offset άνω των 10000 λόγω σάρωσης του πίνακα μέχρι την απαιτούμενη θέση — η βάση δεδομένων διαβάζει όλες τις απορριφθείσες γραμμές.
  • Πρόβλημα συνέπειας — η εισαγωγή και διαγραφή εγγραφών μεταξύ ερωτημάτων οδηγεί σε διπλότυπα και παραλείψεις στα αποτελέσματα σελίδων.
  • Cursor-based σελιδοποίηση λύνει τα προβλήματα του Offset Pagination μέσω δείκτη στην τελευταία εγγραφή αντί για αριθμητική μετατόπιση.
  • Υβριδική προσέγγιση συνδυάζει το offset πρώτης σελίδας με φόρτωση cursor για ατελείωτο scroll σε εφαρμογές κινητών.
  • Σύσταση — χρησιμοποιήστε το Offset Pagination για στατικά σύνολα έως 10000 εγγραφές και μεταβείτε σε δρομείς για μεγάλους όγκους και δυναμικά δεδομένα.

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης