„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > MongoDB entfesseln: Warum die Cursor-basierte Paginierung jedes Mal die Offset-basierte Paginierung übertrifft!

MongoDB entfesseln: Warum die Cursor-basierte Paginierung jedes Mal die Offset-basierte Paginierung übertrifft!

Veröffentlicht am 07.11.2024
Durchsuche:299

Paginierung ist ein wichtiger Teil jeder Datenbankoperation, wenn es um große Datensätze geht. Es ermöglicht Ihnen, Daten in überschaubare Blöcke aufzuteilen und so das Durchsuchen, Verarbeiten und Anzeigen zu vereinfachen. MongoDB bietet zwei gängige Paginierungsmethoden: Offset-basiert und Cursor-basiert. Obwohl beide Methoden denselben Zweck erfüllen, unterscheiden sie sich erheblich in der Leistung und Benutzerfreundlichkeit, insbesondere wenn der Datensatz wächst.

Lassen Sie uns in die beiden Ansätze eintauchen und sehen, warum die Cursor-basierte Paginierung oft die Offset-basierte Paginierung übertrifft.

1. Offsetbasierte Paginierung

Offsetbasierte Paginierung ist unkompliziert. Es ruft eine bestimmte Anzahl von Datensätzen ab einem bestimmten Offset ab. Beispielsweise könnte die erste Seite die Datensätze 0–9 abrufen, die zweite Seite die Datensätze 10–19 und so weiter.

Diese Methode hat jedoch einen erheblichen Nachteil: Wenn Sie zu höheren Seiten wechseln, wird die Abfrage langsamer. Dies liegt daran, dass die Datenbank die Datensätze der vorherigen Seiten überspringen muss, was ein Durchsuchen dieser Datensätze erfordert.

Hier ist der Code für die offsetbasierte Paginierung:

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. Cursorbasierte Paginierung

Cursorbasierte Paginierung, auch Keyset-Paginierung genannt, basiert auf einer eindeutigen Kennung (z. B. einer ID oder einem Zeitstempel), um durch die Datensätze zu paginieren. Anstatt eine bestimmte Anzahl von Datensätzen zu überspringen, wird der zuletzt abgerufene Datensatz als Referenzpunkt für den Abruf des nächsten Satzes verwendet.

Dieser Ansatz ist effizienter, da er die Notwendigkeit vermeidet, die Datensätze vor der aktuellen Seite zu scannen. Dadurch bleibt die Abfragezeit konsistent, unabhängig davon, wie tief Sie in den Datensatz vordringen.

Hier ist der Code für die Cursor-basierte Paginierung:

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);
}

In diesem Beispiel ist lastDocumentId die ID des letzten Dokuments der vorherigen Seite. Bei der Abfrage der nächsten Seite ruft die Datenbank Dokumente mit einer ID ab, die größer als dieser Wert ist, und gewährleistet so einen nahtlosen Übergang zum nächsten Satz von Datensätzen.

3. Leistungsvergleich

Sehen wir uns an, wie diese beiden Methoden bei einem großen Datensatz funktionieren.

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

Im Leistungstest werden Sie feststellen, dass die offsetbasierte Paginierung mit zunehmender Seitenzahl länger dauert, während der Cursor -basierte Paginierung bleibt konsistent und ist daher die bessere Wahl für große Datensätze. Dieses Beispiel zeigt auch die Leistungsfähigkeit der Indizierung. Versuchen Sie, den Index zu entfernen und sehen Sie sich dann auch das Ergebnis an!

Warum die Indizierung wichtig ist

Ohne einen Index müsste MongoDB einen Sammlungsscan durchführen, was bedeutet, dass jedes Dokument in der Sammlung durchsucht werden muss, um die relevanten Daten zu finden. Dies ist ineffizient, insbesondere wenn Ihr Datensatz wächst. Mithilfe von Indizes kann MongoDB effizient die Dokumente finden, die Ihren Abfragebedingungen entsprechen, wodurch die Abfrageleistung erheblich beschleunigt wird.

Im Kontext der Cursor-basierten Paginierung stellt der Index sicher, dass das Abrufen des nächsten Satzes von Dokumenten (basierend auf der Dokument-ID) schnell erfolgt und die Leistung nicht abnimmt, wenn der Sammlung weitere Dokumente hinzugefügt werden.

Abschluss

Obwohl die Offset-basierte Paginierung einfach zu implementieren ist, kann sie bei großen Datensätzen aufgrund der Notwendigkeit, Datensätze zu durchsuchen, ineffizient werden. Die Cursor-basierte Paginierung hingegen bietet eine skalierbarere Lösung und sorgt für eine gleichbleibende Leistung unabhängig von der Datensatzgröße. Wenn Sie mit großen Sammlungen in MongoDB arbeiten, lohnt es sich, die Cursor-basierte Paginierung für ein reibungsloseres und schnelleres Erlebnis in Betracht zu ziehen.

Hier ist die vollständige index.js, die Sie lokal ausführen können:

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"); asynchrone Funktion insertMongoDBRecords() { versuchen { let bulkOps = []; für (sei i = 0; i 0) { Warten Sie auf die Sammlung.bulkWrite(bulkOps); console.log("? Bisher eingefügte Datensätze ->", bulkOps.length); } console.log("MongoDB-Einfügung abgeschlossen"); } fangen (irrt) { console.error("Fehler beim Einfügen von Datensätzen", err); } } asynchrone Funktion offset_based_pagination(params) { const { page = 5, limit = 100 } = params; const skip = (page - 1) * limit; const results =waitcollection.find({}).skip(skip).limit(limit).toArray(); console.log(`Offset-basierte Paginierung (Page ${page}):`, results.length, "page", page, "skip", skip, "limit", limit); } asynchrone Funktion Cursor_based_pagination(params) { const { lastDocumentId, limit = 100 } = params; const query = lastDocumentId ? { documentId: { $gt: lastDocumentId } } : {}; const-Ergebnisse = Sammlung abwarten .find(Abfrage) .sort({ documentId: 1 }) .limit(limit) .toArray(); console.log("Cursorbasierte Paginierung:", results.length); } asynchrone Funktion testMongoDB() { console.time("MongoDB-Einfügezeit:"); Warten auf insertMongoDBRecords(); console.timeEnd("MongoDB-Einfügezeit:"); // Einen Index für das documentId-Feld erstellen Warten Sie auf die Sammlung.createIndex({ documentId: 1 }); console.log("Index für documentId-Feld erstellt"); console.time("Offset-basierte Paginierungszeit:"); wait offset_based_pagination({ page: 2, limit: 250000 }); console.timeEnd("Offset-basierte Paginierungszeit:"); console.time("Cursorbasierte Paginierungszeit:"); wait Cursor_based_pagination({ lastDocumentId: 170000, limit: 250000 }); console.timeEnd("Cursorbasierte Paginierungszeit:"); Warten Sie auf client.close(); } testMongoDB();

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();

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/franklinthaker/unleashing-mongodb-why-cursor-based-pagination-outperforms-offset-based-pagination-every-time-4o30?1 Wenn es einen Verstoß gibt, bitte Kontaktieren Sie Study_golang@163 .comdelete
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3