«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Раскрытие MongoDB: почему пагинация на основе курсора каждый раз превосходит пагинацию на основе смещения!

Раскрытие MongoDB: почему пагинация на основе курсора каждый раз превосходит пагинацию на основе смещения!

Опубликовано 7 ноября 2024 г.
Просматривать:513

Разбиение на страницы – это важная часть любой операции с базой данных при работе с большими наборами данных. Он позволяет разбивать данные на управляемые фрагменты, что упрощает просмотр, обработку и отображение. MongoDB предоставляет два распространенных метода нумерации страниц: на основе смещения и на основе курсора. Хотя оба метода служат одной и той же цели, они значительно различаются по производительности и удобству использования, особенно по мере роста набора данных.

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

1. Разбивка на страницы со смещением

Разбивка на страницы со смещением проста. Он извлекает определенное количество записей, начиная с заданного смещения. Например, первая страница может получать записи 0–9, вторая страница — записи 10–19 и т. д.

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

Вот код для нумерации страниц на основе смещения:

async function offset_based_pagination(params) {
  const { page = 5, limit = 100 } = params;
  const skip = (page - 1) * limit;
  const results = await collection.find({}).skip(skip).limit(limit).toArray();
  console.log(`Offset-based pagination (Page ${page}):`, results.length, "page", page, "skip", skip, "limit", limit);
}

2. Разбивка на страницы с помощью курсора

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

Этот подход более эффективен, поскольку позволяет избежать необходимости сканирования записей перед текущей страницей. В результате время запроса остается постоянным, независимо от того, насколько глубоко вы погружаетесь в набор данных.

Вот код для нумерации страниц на основе курсора:

async function cursor_based_pagination(params) {
  const { lastDocumentId, limit = 100 } = params;
  const query = lastDocumentId ? { documentId: { $gt: lastDocumentId } } : {};
  const results = await collection
    .find(query)
    .sort({ documentId: 1 })
    .limit(limit)
    .toArray();
  console.log("Cursor-based pagination:", results.length);
}

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

3. Сравнение производительности

Давайте посмотрим, как эти два метода работают с большим набором данных.

async function testMongoDB() {
    console.time("MongoDB Insert Time:");
    await insertMongoDBRecords();
    console.timeEnd("MongoDB Insert Time:");

  // Create an index on the documentId field
  await collection.createIndex({ documentId: 1 });
  console.log("Index created on documentId field");

  console.time("Offset-based pagination Time:");
  await offset_based_pagination({ page: 2, limit: 250000 });
  console.timeEnd("Offset-based pagination Time:");

  console.time("Cursor-based pagination Time:");
  await cursor_based_pagination({ lastDocumentId: 170000, limit: 250000 });
  console.timeEnd("Cursor-based pagination Time:");

  await client.close();
}

Image description

В тесте производительности вы заметите, что разбиение на страницы на основе смещения занимает дольше по мере того, как номер страницы увеличивается, тогда как курсор -основанная нумерация страниц остается единообразной, что делает ее лучшим выбором для больших наборов данных. Этот пример также демонстрирует возможности индексации. Попробуйте удалить индекс и посмотреть результат!

Почему индексирование важно

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

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

Заключение

Хотя пагинацию на основе смещения легко реализовать, она может оказаться неэффективной при работе с большими наборами данных из-за необходимости сканирования записей. С другой стороны, нумерация страниц на основе курсора обеспечивает более масштабируемое решение, сохраняя постоянную производительность независимо от размера набора данных. Если вы работаете с большими коллекциями в MongoDB, стоит рассмотреть возможность разбиения на страницы с помощью курсора, чтобы обеспечить более плавную и быструю работу.

Вот полный index.js для локального запуска:

const { MongoClient } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
client.connect();
const db = client.db("testdb");
const collection = db.collection("testCollection");

async function insertMongoDBRecords() {
  try {
    let bulkOps = [];

    for (let i = 0; i  0) {
      await collection.bulkWrite(bulkOps);
      console.log("? Inserted records till now -> ", bulkOps.length);
    }

    console.log("MongoDB Insertion Completed");
  } catch (err) {
    console.error("Error in inserting records", err);
  }
}

async function offset_based_pagination(params) {
  const { page = 5, limit = 100 } = params;
  const skip = (page - 1) * limit;
  const results = await collection.find({}).skip(skip).limit(limit).toArray();
  console.log(`Offset-based pagination (Page ${page}):`, results.length, "page", page, "skip", skip, "limit", limit);
}

async function cursor_based_pagination(params) {
  const { lastDocumentId, limit = 100 } = params;
  const query = lastDocumentId ? { documentId: { $gt: lastDocumentId } } : {};
  const results = await collection
    .find(query)
    .sort({ documentId: 1 })
    .limit(limit)
    .toArray();
  console.log("Cursor-based pagination:", results.length);
}

async function testMongoDB() {
  console.time("MongoDB Insert Time:");
  await insertMongoDBRecords();
  console.timeEnd("MongoDB Insert Time:");

  // Create an index on the documentId field
  await collection.createIndex({ documentId: 1 });
  console.log("Index created on documentId field");

  console.time("Offset-based pagination Time:");
  await offset_based_pagination({ page: 2, limit: 250000 });
  console.timeEnd("Offset-based pagination Time:");

  console.time("Cursor-based pagination Time:");
  await cursor_based_pagination({ lastDocumentId: 170000, limit: 250000 });
  console.timeEnd("Cursor-based pagination Time:");

  await client.close();
}

testMongoDB();

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/franklinthaker/unleashing-mongodb-why-cursor-based-pagination-outperforms-offset-based-pagination-every-time-4o30?1 Если есть какие-либо нарушения, пожалуйста, свяжитесь с Study_golang@163 .comdelete
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3