Пагинация в БД без offset. Работаем с запросами

Поделиться
HTML-код
  • Опубликовано: 13 янв 2025

Комментарии • 34

  • @ИгорьСеверюхин
    @ИгорьСеверюхин 2 года назад +3

    Уже несколько лет применяем подобную пагинацию на своих проектах в компании. Mysql по обычному числовому идентификатору (таблицы более 500к записей) и в MongoDB по ObjectId (коллекции на пару десятков миллионов записей) - работает отлично. А вот в одном из проектов в таблице на 200к записей пагинация через обычный limit\offset стандартными средствами php-фреймворка. И вот там очень ощущается деградация скорости выполнения запроса ближе к последней трети. Наверное, стоит еще отметить, что для поля для курсора требуется индекс. Спасибо за видео!

    • @petery6775
      @petery6775 Год назад

      а почему нельзя просто ID сравнивать ? сделав его big int ? без кортежного сравнения и обойтись 1 полем

  • @delay_gryaz_chisto
    @delay_gryaz_chisto 3 года назад +11

    называется это курсорная пагинация. проще объяснить так: мы ставим курсор на какую-то последнюю запись(которую приняли в квери-параметре хендлера из урла), и говорим: ОТДАЙ НАМ СЛЕДУЮЩИЕ %LIMIT%(предположим, три). ну оно и отдает. тем самым не прогружая всю БД как в случае с оффсетом. и считается хорошей практикой отдавать в ответе клиенту в жсоне поля next и prev путь на следующую/предыдущую страницу, где квери-параметры(в ссылке) next/prev - это base64 айдишников.
    ну а если бы id был интом, то сравнение с датой было бы лишнее лишнее. инта достаточно.
    за видео спасибо.

  • @Rryowa
    @Rryowa 6 месяцев назад +1

    Господь храни тебя и твой канал, ничего более информативного и интересного по гошке не видел, надеюсь ты когда-нибудь вернешься...

  • @MaxShcherbakov
    @MaxShcherbakov 3 года назад +14

    Идентификатор в примере либо лишний, либо не того типа, ибо сравнение картежа, где есть UUID не имеет смысла, имхо. В примере с сайта что вы показывали скорее всего используется числовой идентификатор, скорее всего автогенерация по Seq, чтобы каждая новая запись имела следующий номер, тогда сравнение картежей имеет смысл.

  • @TheArtofDevelopment
    @TheArtofDevelopment  3 года назад +6

    Что скажете по поводу такой пагинации?
    P.S. на этот раз вместо вебки телефон, но помешали тени. некст тайм включу софтбоксы

  • @dmitriyobidin6049
    @dmitriyobidin6049 3 года назад +4

    Интересный приём, действительно должно быстрее работать.
    Пара вопросов возникает:
    1) Guid в качестве уникального идентификатора. При использовании гуида не стоит ожидать, что порядок выбора записей для пагинации будет совпадать с порядком того, как записи лежат в таблице. Хотя по факту работать будет и записи не пропустит(вроде как), но семантически может выглядеть странно, например, порядок книг будет выводится не в алфавитном порядке(не в том порядке, как мы их добавляли).
    2) Было бы более показательно и всеообъемлюще, если бы в примере был не таймстемп, а просто дата. Т.е. если бы в примере были записи в одинаковыми значениями в поле даты. А то так получается, что у всех записей во всех полях значения уникальные. Тут хоть по чему сортируй - получишь корректную(с точки зрения отсутствия пропусков) пагинацию.
    3) Получается что необходимо хранить стейт на стороне сервера? Или наоборот со стороны клиента передавать значения из последней полученной записи?

  • @sovrinfo
    @sovrinfo 2 года назад +1

    Спасибо за видео. Коммент в поддержку!

  • @andreybalatsan9336
    @andreybalatsan9336 6 месяцев назад +1

    Я только начинаю изучать гошку, для меня выглядит это как игра в наперстки с уличным жуликом. И я такой - Это магия... Но в конце всё понял

  • @rumartru
    @rumartru 3 года назад +2

    Спасибо! Теперь я знаю почему у меня борода не растет 😂

  • @alekssjeva951
    @alekssjeva951 Год назад +1

    Этот вариант не подходит, если нужна классическая пагинация (в виде ссылок на страницы пагинации). А так давно заметил, что даже при небольших значениях OFFSET (10-15), запрос в MySQL выполняется значительно медленнее, чем без OFFSET

  • @xtech3408
    @xtech3408 Год назад +1

    Почему во время интерпретации на ключевое слово offset, СУБД под капотом не делает тоже самое, если так быстрее? И что такого делает offset, что получается медленнее. СУБД типа сначала всю таблицу выгружает, а потом лишнее выкидывает? Поэтому?

    • @alvcode3764
      @alvcode3764 10 месяцев назад

      потому что субд не ванга, откуда она знает, что ей делать надо. на то и нужны команды. offset по сути отсчитывает все записи до указанного смещения. если задал offset 100000 limit 10, то по сути базе надо отсчитать все записи, пока не будет по счету 100к и начиная со следующей отдаст 10 записей. а существует какое-то доп.условие WHERE, то скорость намного ухудшается. например когда надо достать просто 10 записей по условию WHERE, то база найдет первые 10 попавшихся и отдаст их, а тут она должна найти все 100к подходящие под условие WHERE и только следующие 10 отдать

  • @sergeyfilatov3027
    @sergeyfilatov3027 3 года назад +2

    Получается что вместо
    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

    • @BabaykaMoscow
      @BabaykaMoscow 2 года назад

      А ты попробуй сгенери таблицу с 10 миллионами записей и попробуй бабахнуть в ней оффсетом начиная с 9 миллионной записи. И каунт до кучи сделай. И сразу станет понятно, что все это перестаёт нормально работать :)

  • @bunchatests
    @bunchatests 10 месяцев назад

    интересно, можно ли сделать пагинацию без ORDER BY?

  • @petery6775
    @petery6775 Год назад

    а почему нельзя просто ID сравнивать ? сделав его big int ? без кортежного сравнения и обойтись 1 полем

  • @eamarc
    @eamarc 3 года назад +3

    Можно всю эту логику в функцию на БД засунуть. Типа `SELECT get_books(1, 10) ` чтоб было хорошо и беку и фронту.

  • @АйтишныйЧел2
    @АйтишныйЧел2 2 года назад +1

    А как на клиенте показывать сколько всего есть страниц, если не использовать count(*)?

    • @TheArtofDevelopment
      @TheArtofDevelopment  2 года назад

      А точно ли есть такая задача?
      Обычно эта цифра на самом деле не нужна, если коллекция огромная (сотни тысяч записей), ну если вы не гугл, конечно.
      Но если нужна - то конечно делать count(*)

    • @АйтишныйЧел2
      @АйтишныйЧел2 2 года назад

      @@TheArtofDevelopment Спасибо!

  • @ksivvi0
    @ksivvi0 2 года назад +1

    привет! немного критики, не обессудь...
    видео кажется затянутым, и если бы я совсем не понимал данную тему, вряд-ли бы понял.
    т к в данном видео ничего не сказано про индексы, то лучше использовать limit offset)

  • @kumb61
    @kumb61 2 года назад +1

    Очень долго, это можно было в минут 5 уложить.
    А так идея интересная, получается это на беке нужно всегда сохранять ключи последней записи?
    Думаю что скорость достигается за счет того, что при миллионах записей вместо последовательного пропуска от OFFSET отрабатывается какой нибудь бинарный поиск по индексу.

  • @ruslanroot
    @ruslanroot 3 года назад +2

    главное чтоб пользователь не нажал переход на 69 страницу, сразу с первой ;)

    • @denisromanov9367
      @denisromanov9367 3 года назад +2

      Это просто порционная выдача пачки данных, а не "навигация" по пагинации.
      В хайлоад на 69 странице, раз в долю секунды будут меняться данные ;)

  • @aleksandrsu998
    @aleksandrsu998 2 года назад +1

    Это всё хорошо, но мы не можем взять и перейти сразу на тысячную страницу. И не знаем их общее количество.

    • @TheArtofDevelopment
      @TheArtofDevelopment  2 года назад

      а есть такая задача? если есть ее можно решить иначе

    • @no1621name
      @no1621name 2 года назад +1

      @@TheArtofDevelopment не подскажите, как?

    • @TheArtofDevelopment
      @TheArtofDevelopment  2 года назад +1

      стандартно, через limit и offset

    • @no1621name
      @no1621name 2 года назад

      @@TheArtofDevelopment хорошо, спасибо

  • @ПавелСироткин-м5е
    @ПавелСироткин-м5е 2 года назад +1

    Не могу понять что так все любят пихать в поле примари кей тип uuid когда он в бд 128 бит занимает, что как бы много, тот же биг инт будет занимать в 2 раза меньше

    • @vadimburavlev4773
      @vadimburavlev4773 Год назад

      потому что автоинкримент на id не всегда решает все виды задач.
      в распределенных действительно больших системах получать автоинкрементный id становится большой болью. когда нужно спрятать последовательность выдачи id тоже подходит uuid, его можно получать с timestamp - uuid 7 версии, есть uuid с hash. Все зависит от решаемой задачи.