"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > إطلاق العنان لـ MongoDB: لماذا يتفوق ترقيم الصفحات المستند إلى المؤشر على ترقيم الصفحات المستند إلى الأوفست في كل مرة!

إطلاق العنان لـ MongoDB: لماذا يتفوق ترقيم الصفحات المستند إلى المؤشر على ترقيم الصفحات المستند إلى الأوفست في كل مرة!

تم النشر بتاريخ 2024-11-07
تصفح:545

يعد ترقيم الصفحات جزءًا مهمًا من أي عملية قاعدة بيانات عند التعامل مع مجموعات البيانات الكبيرة. فهو يسمح لك بتقسيم البيانات إلى أجزاء يمكن التحكم فيها، مما يسهل التصفح والمعالجة والعرض. يوفر 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 بالعثور بكفاءة على المستندات التي تطابق شروط الاستعلام الخاص بك، مما يؤدي إلى تسريع أداء الاستعلام بشكل ملحوظ.

في سياق ترقيم الصفحات المستند إلى المؤشر، يضمن الفهرس أن جلب المجموعة التالية من المستندات (استنادًا إلى documentId) يكون سريعًا ولا يتدهور الأداء عند إضافة المزيد من المستندات إلى المجموعة.

خاتمة

على الرغم من سهولة تنفيذ نظام ترقيم الصفحات القائم على الإزاحة، إلا أنه قد يصبح غير فعال مع مجموعات البيانات الكبيرة بسبب الحاجة إلى فحص السجلات. من ناحية أخرى، يوفر ترقيم الصفحات المستند إلى المؤشر حلاً أكثر قابلية للتطوير، مما يحافظ على اتساق الأداء بغض النظر عن حجم مجموعة البيانات. إذا كنت تعمل مع مجموعات كبيرة في 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 إذا كان هناك أي انتهاك، من فضلك اتصل بـ [email protected]
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3