Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як влаштована пагінація великих таблиць і чому offset повільний?

Laravel дає три способи гортати вибірку, і вони по-різному поводяться на великих таблицях.

paginate() - класична пагінація з номерами сторінок:

$posts = Post::latest()->paginate(15);

Виконує два запити: сам вибір і count(*) для загальної кількості сторінок.

simplePaginate() - те саме без підрахунку загальної кількості, лише «далі/назад». Прибирає дорогий count(*) на великій таблиці.

cursorPaginate() - гортання за значенням ключа, без offset:

$posts = Post::latest()->cursorPaginate(15);

Чому offset повільний. limit 15 offset 100000 не перестрибує рядки - база читає й відкидає сто тисяч, перш ніж віддати п'ятнадцять. Що глибша сторінка, то повільніше; на останніх сторінках великого списку це секунди.

Курсорна пагінація натомість запитує «наступні 15 після цього значення»:

where (published_at, id) < (?, ?) order by published_at desc, id desc limit 15

Час не залежить від глибини - за умови, що є індекс на колонках сортування.

Друга перевага - стабільність. З offset новий запис, доданий між переглядами сторінок, зсуває всю вибірку, і один запис читач побачить двічі, а інший пропустить. Курсор до цього стійкий.

Ціна курсора: немає номерів сторінок і переходу «на сторінку 7» - лише вперед і назад. Сортування має бути за унікальною чи доповненою id комбінацією, інакше рядки з однаковим значенням загубляться.

Що обирати: адмінка з номерами сторінок - paginate(); довга стрічка чи API - cursorPaginate(); проміжний варіант, де потрібні лише «далі/назад» - simplePaginate().

Докладніше в документації: Пагінація

Схожі питання