TG Telegram Group & Channel
.NET Разработчик | United States America (US)
Create: Update:

День 2277. #ЗаметкиНаПолях
Разбираем Курсорную Пагинацию. Продолжение

Начало

Курсорная пагинация
Курсорная пагинация использует контрольную точку (курсор) для извлечения следующего набора результатов. Эта контрольная точка обычно является уникальным идентификатором или комбинацией полей, которые определяют порядок сортировки.

Используем поля Date и Id для создания курсора для нашей таблицы UserNotes. Курсор представляет собой композицию этих двух полей, что позволяет нам эффективно выполнять пагинацию:

var query = dbContext.UserNotes.AsQueryable();

if (date != null && lastId != null)
{
// Используем курсор для извлечения части результатов
// При прямой сортировке нужно заменить > на <
query = query
.Where(x => x.Date < date ||
(x.Date == date && x.Id <= lastId));
}

// Извлекаем элементы на 1 больше
var items = await query
.OrderByDescending(x => x.Date)
.ThenByDescending(x => x.Id)
.Take(limit + 1)
.ToListAsync(cancellationToken);

// Определяем данные для следующей страницы
var hasMore = items.Count > limit;
DateOnly? nextDate =
hasMore ? items[^1].Date : null;
Guid? nextId =
hasMore ? items[^1].Id : null;

// Удаляем «лишний» результат, если он есть
if (hasMore)
items.RemoveAt(items.Count - 1);

Порядок сортировки такой же, как в примере офсетной пагинации. Однако порядок сортировки имеет решающее значение для согласованных результатов при курсорной пагинации. Поскольку Date не является уникальным значением в нашей таблице, мы используем поле Id для обработки границ страниц. Это гарантирует, что мы не пропустим и не продублируем элементы при пагинации. Вот сгенерированный SQL (PostgreSql) для курсорной пагинации:
SELECT u.id, u.date, u.note, u.user_id
FROM user_notes AS u
WHERE u.date < @date OR (u.date = @date AND u.id <= @lastId)
ORDER BY u.date DESC, u.id DESC
LIMIT @limit;

Обратите внимание, что в запросе нет OFFSET. Производительность с курсорной пагинацией постоянна независимо от страницы, потому что мы напрямую ищем строки на основе значений курсора, что более эффективно, чем использование OFFSET. Это огромное преимущество перед офсетной пагинацией, особенно для больших наборов данных.

Запрос COUNT при курсорной пагинации также не нужен, поскольку мы не подсчитываем общее количество элементов. Хотя, он может потребоваться, если вам нужно отобразить общее количество страниц заранее.

Ограничения курсорной пагинации:
- Если пользователям необходимо динамически изменять поля сортировки, курсорная пагинация становится значительно сложнее, поскольку курсор должен включать все условия сортировки;
- Пользователи не могут перейти к определённому номеру страницы — они должны последовательно проходить по страницам;
- Сложнее реализовать правильно по сравнению с офсетной пагинацией, особенно при обработке границ страниц и обеспечении различной сортировки.

Окончание следует…

Источник:
https://www.milanjovanovic.tech/blog/understanding-cursor-pagination-and-why-its-so-fast-deep-dive

День 2277. #ЗаметкиНаПолях
Разбираем Курсорную Пагинацию. Продолжение

Начало

Курсорная пагинация
Курсорная пагинация использует контрольную точку (курсор) для извлечения следующего набора результатов. Эта контрольная точка обычно является уникальным идентификатором или комбинацией полей, которые определяют порядок сортировки.

Используем поля Date и Id для создания курсора для нашей таблицы UserNotes. Курсор представляет собой композицию этих двух полей, что позволяет нам эффективно выполнять пагинацию:
var query = dbContext.UserNotes.AsQueryable();

if (date != null && lastId != null)
{
// Используем курсор для извлечения части результатов
// При прямой сортировке нужно заменить > на <
query = query
.Where(x => x.Date < date ||
(x.Date == date && x.Id <= lastId));
}

// Извлекаем элементы на 1 больше
var items = await query
.OrderByDescending(x => x.Date)
.ThenByDescending(x => x.Id)
.Take(limit + 1)
.ToListAsync(cancellationToken);

// Определяем данные для следующей страницы
var hasMore = items.Count > limit;
DateOnly? nextDate =
hasMore ? items[^1].Date : null;
Guid? nextId =
hasMore ? items[^1].Id : null;

// Удаляем «лишний» результат, если он есть
if (hasMore)
items.RemoveAt(items.Count - 1);

Порядок сортировки такой же, как в примере офсетной пагинации. Однако порядок сортировки имеет решающее значение для согласованных результатов при курсорной пагинации. Поскольку Date не является уникальным значением в нашей таблице, мы используем поле Id для обработки границ страниц. Это гарантирует, что мы не пропустим и не продублируем элементы при пагинации. Вот сгенерированный SQL (PostgreSql) для курсорной пагинации:
SELECT u.id, u.date, u.note, u.user_id
FROM user_notes AS u
WHERE u.date < @date OR (u.date = @date AND u.id <= @lastId)
ORDER BY u.date DESC, u.id DESC
LIMIT @limit;

Обратите внимание, что в запросе нет OFFSET. Производительность с курсорной пагинацией постоянна независимо от страницы, потому что мы напрямую ищем строки на основе значений курсора, что более эффективно, чем использование OFFSET. Это огромное преимущество перед офсетной пагинацией, особенно для больших наборов данных.

Запрос COUNT при курсорной пагинации также не нужен, поскольку мы не подсчитываем общее количество элементов. Хотя, он может потребоваться, если вам нужно отобразить общее количество страниц заранее.

Ограничения курсорной пагинации:
- Если пользователям необходимо динамически изменять поля сортировки, курсорная пагинация становится значительно сложнее, поскольку курсор должен включать все условия сортировки;
- Пользователи не могут перейти к определённому номеру страницы — они должны последовательно проходить по страницам;
- Сложнее реализовать правильно по сравнению с офсетной пагинацией, особенно при обработке границ страниц и обеспечении различной сортировки.

Окончание следует…

Источник:
https://www.milanjovanovic.tech/blog/understanding-cursor-pagination-and-why-its-so-fast-deep-dive


>>Click here to continue<<

.NET Разработчик




Share with your best friend
VIEW MORE

United States America Popular Telegram Group (US)