Пагинация в БД без offset. Работаем с запросами
HTML-код
- Опубликовано: 25 авг 2024
- В этом ролике мы посмотрим на способ организации пагинации без ключевого слова offset.
Пагинация это порционная выдача данных из БД.
Больше обо мне и курсах можно прочитать здесь:
artofedu.org/
Приятного просмотра!
Use the Index, Luke!
use-the-index-...
May the index be with you!
Поддержи выход новых видео на Патреоне!
/ theartofdevelopment
Другие видео:
Уроки по Golang. Advanced. REST API. Вебсервер.
• Уроки по Golang. Advan...
Изучаем Python. Урок 1. Основы. Бонус: Пишем приложение на FastAPI • Изучаем Python. Урок 1...
Изучаем Golang. Урок 1. Основы + веб-сервер в 3 строки в конце урока! • Изучаем Golang. Урок 1...
Разработка системы заметок на Python, Golang и микросервисы в 2021 году • Разработка системы зам...
Как стать разработчиком. Часть 1 • Как стать разработчико...
Что такое микросервисы за 200 секунд • Что такое микросервисы...
Что такое Apache Kafka за 200 секунд • Что такое Apache Kafka...
Telegram Group: t.me/theartofd...
VK: thearto...
Дружественный Golang чат: t.me/gogolang
----
Меня зовут Артур Карапетов и я занимаюсь всем, что связано с разработкой. Я создаю высоконагруженные информационные системы, стартапы, занимаюсь личным обучением людей в сфере разработки (программисты, аналитики, системные администраторы), также я помогаю компаниям и стартапам с обучением людей работать и повышением их квалификации, об этом можно почитать здесь: mitkadr.ru.
На этом канале я выкладываю ролики на интересующие меня темы, здесь можно найти серию роликов про создание информационной системы с нуля, а также можно найти серию уроков по языкам, которые я люблю. Добро пожаловать и хорошего просмотра!
#golang #урок #restapi #rest #микросервисы #microservices #jetbrains #goland #tutorial #голенг #development #howto #learnbasics #coding #programming #изучаемIT #программирование #разработка
Уже несколько лет применяем подобную пагинацию на своих проектах в компании. Mysql по обычному числовому идентификатору (таблицы более 500к записей) и в MongoDB по ObjectId (коллекции на пару десятков миллионов записей) - работает отлично. А вот в одном из проектов в таблице на 200к записей пагинация через обычный limit\offset стандартными средствами php-фреймворка. И вот там очень ощущается деградация скорости выполнения запроса ближе к последней трети. Наверное, стоит еще отметить, что для поля для курсора требуется индекс. Спасибо за видео!
а почему нельзя просто ID сравнивать ? сделав его big int ? без кортежного сравнения и обойтись 1 полем
называется это курсорная пагинация. проще объяснить так: мы ставим курсор на какую-то последнюю запись(которую приняли в квери-параметре хендлера из урла), и говорим: ОТДАЙ НАМ СЛЕДУЮЩИЕ %LIMIT%(предположим, три). ну оно и отдает. тем самым не прогружая всю БД как в случае с оффсетом. и считается хорошей практикой отдавать в ответе клиенту в жсоне поля next и prev путь на следующую/предыдущую страницу, где квери-параметры(в ссылке) next/prev - это base64 айдишников.
ну а если бы id был интом, то сравнение с датой было бы лишнее лишнее. инта достаточно.
за видео спасибо.
Господь храни тебя и твой канал, ничего более информативного и интересного по гошке не видел, надеюсь ты когда-нибудь вернешься...
Интересный приём, действительно должно быстрее работать.
Пара вопросов возникает:
1) Guid в качестве уникального идентификатора. При использовании гуида не стоит ожидать, что порядок выбора записей для пагинации будет совпадать с порядком того, как записи лежат в таблице. Хотя по факту работать будет и записи не пропустит(вроде как), но семантически может выглядеть странно, например, порядок книг будет выводится не в алфавитном порядке(не в том порядке, как мы их добавляли).
2) Было бы более показательно и всеообъемлюще, если бы в примере был не таймстемп, а просто дата. Т.е. если бы в примере были записи в одинаковыми значениями в поле даты. А то так получается, что у всех записей во всех полях значения уникальные. Тут хоть по чему сортируй - получишь корректную(с точки зрения отсутствия пропусков) пагинацию.
3) Получается что необходимо хранить стейт на стороне сервера? Или наоборот со стороны клиента передавать значения из последней полученной записи?
Спасибо за видео. Коммент в поддержку!
Идентификатор в примере либо лишний, либо не того типа, ибо сравнение картежа, где есть UUID не имеет смысла, имхо. В примере с сайта что вы показывали скорее всего используется числовой идентификатор, скорее всего автогенерация по Seq, чтобы каждая новая запись имела следующий номер, тогда сравнение картежей имеет смысл.
Я только начинаю изучать гошку, для меня выглядит это как игра в наперстки с уличным жуликом. И я такой - Это магия... Но в конце всё понял
Что скажете по поводу такой пагинации?
P.S. на этот раз вместо вебки телефон, но помешали тени. некст тайм включу софтбоксы
Спасибо! Теперь я знаю почему у меня борода не растет 😂
Этот вариант не подходит, если нужна классическая пагинация (в виде ссылок на страницы пагинации). А так давно заметил, что даже при небольших значениях OFFSET (10-15), запрос в MySQL выполняется значительно медленнее, чем без OFFSET
Получается что вместо
select * from video order by created desc offset 0 limit 10
нам предлагают делать
select * from video where created < {last_created} order by created desc limit 10
что означает что на клиенте нужно хранить не page_id, а данные всех полей по которым идет сортировка
Ну ок, классно, что есть такой вариант.
Но я думаю это уже немного относится к ранней оптимизации.
То есть, я бы так делал если бы я реально понимал, что для меня это важно, в других случаях бы не заморачивался.
p. s. про кортежное сравнение первый раз узнал xD
А ты попробуй сгенери таблицу с 10 миллионами записей и попробуй бабахнуть в ней оффсетом начиная с 9 миллионной записи. И каунт до кучи сделай. И сразу станет понятно, что все это перестаёт нормально работать :)
привет! немного критики, не обессудь...
видео кажется затянутым, и если бы я совсем не понимал данную тему, вряд-ли бы понял.
т к в данном видео ничего не сказано про индексы, то лучше использовать limit offset)
Почему во время интерпретации на ключевое слово offset, СУБД под капотом не делает тоже самое, если так быстрее? И что такого делает offset, что получается медленнее. СУБД типа сначала всю таблицу выгружает, а потом лишнее выкидывает? Поэтому?
потому что субд не ванга, откуда она знает, что ей делать надо. на то и нужны команды. offset по сути отсчитывает все записи до указанного смещения. если задал offset 100000 limit 10, то по сути базе надо отсчитать все записи, пока не будет по счету 100к и начиная со следующей отдаст 10 записей. а существует какое-то доп.условие WHERE, то скорость намного ухудшается. например когда надо достать просто 10 записей по условию WHERE, то база найдет первые 10 попавшихся и отдаст их, а тут она должна найти все 100к подходящие под условие WHERE и только следующие 10 отдать
интересно, можно ли сделать пагинацию без ORDER BY?
Очень долго, это можно было в минут 5 уложить.
А так идея интересная, получается это на беке нужно всегда сохранять ключи последней записи?
Думаю что скорость достигается за счет того, что при миллионах записей вместо последовательного пропуска от OFFSET отрабатывается какой нибудь бинарный поиск по индексу.
Можно всю эту логику в функцию на БД засунуть. Типа `SELECT get_books(1, 10) ` чтоб было хорошо и беку и фронту.
главное чтоб пользователь не нажал переход на 69 страницу, сразу с первой ;)
Это просто порционная выдача пачки данных, а не "навигация" по пагинации.
В хайлоад на 69 странице, раз в долю секунды будут меняться данные ;)
А как на клиенте показывать сколько всего есть страниц, если не использовать count(*)?
А точно ли есть такая задача?
Обычно эта цифра на самом деле не нужна, если коллекция огромная (сотни тысяч записей), ну если вы не гугл, конечно.
Но если нужна - то конечно делать count(*)
@@TheArtofDevelopment Спасибо!
а почему нельзя просто ID сравнивать ? сделав его big int ? без кортежного сравнения и обойтись 1 полем
можно
Это всё хорошо, но мы не можем взять и перейти сразу на тысячную страницу. И не знаем их общее количество.
а есть такая задача? если есть ее можно решить иначе
@@TheArtofDevelopment не подскажите, как?
стандартно, через limit и offset
@@TheArtofDevelopment хорошо, спасибо
Не могу понять что так все любят пихать в поле примари кей тип uuid когда он в бд 128 бит занимает, что как бы много, тот же биг инт будет занимать в 2 раза меньше
потому что автоинкримент на id не всегда решает все виды задач.
в распределенных действительно больших системах получать автоинкрементный id становится большой болью. когда нужно спрятать последовательность выдачи id тоже подходит uuid, его можно получать с timestamp - uuid 7 версии, есть uuid с hash. Все зависит от решаемой задачи.