Завантаження публікації
ОГОЛОШЕННЯ

Pagination у Laravel: offset vs cursor — у чому різниця і коли яка підходить

Концептуально й практично: чому offset-пагінація “вмирає” на великих таблицях, як cursor-пагінація дає стабільну швидкість, які в неї обмеження, і як правильно обирати під адмінку та стрічки новин.


Максим Третяк
Максим Третяк
Газета Дейком | 05.01.2026, 16:00 GMT+3; 09:00 GMT-4

Пагінація здається дрібницею, поки даних мало. Але як тільки таблиця виростає до сотень тисяч або мільйонів рядків, пагінація стає одним із головних джерел повільності й “дивної” поведінки. Є два базові підходи: offset pagination (класична “сторінка 1/2/3” через OFFSET) і cursor pagination (перегортання “далі/назад” через курсор — значення останнього елемента). Важливо розуміти, що вони вирішують різні задачі, і вибір впливає на швидкість, стабільність результатів і UX.

Offset-пагінація — це те, що ви бачите майже всюди за замовчуванням: page=10 означає “пропусти перші 9 сторінок і покажи наступні 50”. На рівні SQL це LIMIT 50 OFFSET 450. Перевага очевидна: можна перейти на конкретну сторінку, можна показати “сторінка 1 з 200”, можна порахувати загальну кількість. Саме тому вона зручна для адмінки, де люди реально користуються “перейти на сторінку N” і їм важливо бачити total.

Але у offset є фундаментальна проблема продуктивності: чим далі сторінка, тим дорожче. Базі потрібно “пройти” багато рядків, щоб дійти до потрібного offset. Навіть якщо індекс є, глибокий OFFSET змушує базу робити зайву роботу. На сторінці 1 усе швидко. На сторінці 500 — вже помітно. На сторінці 5000 — боляче. У реальних стрічках і логах це стає блокером.

Друга проблема offset-пагінації — нестабільність результатів при змінах даних. Якщо між вашими запитами з’явилися нові записи або змінився порядок сортування, записи можуть “перескочити” між сторінками: ви бачите дублікати або пропуски. Це особливо видно у стрічках новин, де постійно додаються записи, і у логах активності.

Cursor-пагінація працює інакше. Ви не кажете “пропусти N рядків”. Ви кажете “дай наступні 50 після цього конкретного елемента”. Тобто курсор — це мітка позиції в упорядкованому наборі. Зазвичай курсор будується з поля сортування (наприклад, published_at) і унікального tiebreaker (наприклад, id). На рівні SQL це виглядає як WHERE (published_at, id) < (:lastPublishedAt, :lastId) ORDER BY published_at DESC, id DESC LIMIT 50. База може дуже ефективно використати індекс і одразу “приземлитися” в потрібне місце без проходу тисяч рядків.

Головна перевага cursor — стабільна швидкість на будь-якій “глибині”. Ви можете перегорнути 10 000 сторінок “далі”, і кожен запит буде приблизно однаково швидким (за умови правильного індексу). Друга перевага — менше “скачків” і дублікатів при додаванні нових записів, якщо курсор побудований правильно, бо ви рухаєтесь від конкретної точки, а не від “умовного номера сторінки”.

Але cursor має обмеження, які часто критичні для адмінки. Перше — зазвичай немає “перейти на сторінку 123”. Є “далі/назад” по курсору. Друге — складно/дорого показувати “з 1 000 000 записів”, бо cursor не орієнтований на total count. Третє — курсор вимагає стабільного, детермінованого сортування. Ви маєте завжди сортувати за фіксованим набором полів і мати унікальний tiebreaker, інакше курсор може давати пропуски/дублікати.

Тому правильний вибір залежить від сценарію. Для стрічки новин, логів, activity feed, нескінченного скролу, API для мобільного додатку — cursor майже завжди кращий. Він швидкий і стабільний на великій глибині. Для адмінки, де потрібні “сторінки”, фільтри, total count, і де глибоке листання не таке часте — offset залишається нормальним вибором, але з умовою: ви не повинні допускати “гігантського” листання на тисячі сторінок як основний UX. Якщо даних багато — адмінку краще змушувати фільтрувати, а не листати без кінця.

Є ще одна важлива деталь: cursor-пагінація найкраще працює, коли ваш ORDER BY відповідає індексу. Наприклад, якщо ви сортуєте за published_at desc, id desc, то індекс по (published_at, id) дає максимальний ефект. Якщо ви дозволяєте користувачу сортувати “як завгодно” (по назві, по автору, по статусу), cursor стає складнішим: під кожне сортування потрібна своя стратегія і часто свій індекс. Тому cursor добре поєднується з “стрічками”, де порядок майже завжди один — за датою.

Концептуальна рекомендація “на майбутнє” для вашого типу проєкту така. Для публічних стрічок/архівів/логів активності, де даних дуже багато і потрібна стабільна швидкість — плануйте cursor. Для адмінських списків з фільтрами, де важливо бачити загальну кількість і переходити по сторінках — offset, але з правильною індексацією і дисципліною фільтрів. Якщо помітили, що offset став повільним через глибокі сторінки, це не привід одразу “переписати на cursor”, це привід змінити UX: додати фільтри, обмежити глибину або додати “перейти за датою/ID”.

Висновок: offset-пагінація зручна для адмінки і “сторінок”, але дорожчає з глибиною і може давати нестабільні результати при активних змінах даних. Cursor-пагінація швидка й стабільна на великих обсягах, але гірше підходить для випадків, де потрібні номер сторінки і total count. Вибір робиться не “яка модніша”, а під конкретний сценарій і майбутній розмір даних.


Максим Третяк — Кореспондент, який спеціалізується на суспільно важливих темах, пише про політику, фінансові ринки та економіку. Він проживає та працює в Україні.

Цей матеріал є частиною розгорнутої теми: Web-програмування, яка охоплює численні цікаві аспекти цієї події. Газета «Дейком» ретельно відстежує події, проводячи перевірку джерел та інформації, щоб забезпечити нашим читачам найбільш точне та актуальне інформування.

Цей матеріал опубліковано 05.01.2026 року о 16:00 GMT+3 Київ; 09:00 GMT-4 Вашингтон, розділ: Освіта, із заголовком: "Pagination у Laravel: offset vs cursor — у чому різниця і коли яка підходить". Якщо в публікації з'являться зміни, про це буде зазначено та описано у кінці публікації.

Читайте щоденну газету та загальну стрічку новин газети Дейком, яка поєднує багато цікавого в понад 40 розділах з усіх куточків світу.


Save
ОГОЛОШЕННЯ

Новини, які можуть Вас зацікавити:

Штатні та позаштатні журналісти газети «Дейком» щодня готують сотні публікацій, щоб читачі отримували найоперативнішу, перевірену й глибоку інформацію. Ми працюємо для тих, хто хоче розуміти суть подій, бачити широку картину та бути на крок попереду.

Останні новини

Вибір редакції