ページネーション は、大規模なデータセットを扱う場合のデータベース操作の重要な部分です。データを管理可能なチャンクに分割できるため、参照、処理、表示が容易になります。 MongoDB は、オフセット ベースとカーソル ベースという 2 つの一般的なページネーション メソッドを提供します。どちらの方法も同じ目的を果たしますが、特にデータセットが大きくなるにつれて、パフォーマンスと使いやすさが大きく異なります。
2 つのアプローチを詳しく見て、なぜカーソルベースのページネーションがオフセットベースのページネーションよりも優れているのかを見てみましょう。1.
ただし、この方法には重大な欠点があります。上位のページに移動すると、クエリが遅くなります。これは、データベースが前のページのレコードをスキップする必要があり、レコードをスキャンする必要があるためです。
オフセットベースのページネーションのコードは次のとおりです:
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); }
lastDocumentId は前のページの最後のドキュメントの ID です。次のページをクエリする場合、データベースはこの値より大きい ID を持つドキュメントをフェッチし、次のレコード セットへのシームレスな移行を保証します。
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(); }
パフォーマンス テストでは、オフセット ベースのページネーションでは、ページ番号が増えるにつれて時間が長くなりますが、カーソルの場合は時間がかかることがわかります。 -ベースのページネーションは一貫性を維持するため、大規模な
データセットに適しています。この例では、インデックス作成の力も示しています。インデックスを削除して、結果も確認してみてください!
インデックスがないと、MongoDB はコレクション スキャンを実行する必要があります。つまり、コレクション内の各ドキュメントを調べて、関連するデータを見つける必要があります。これは、特にデータセットが増大する場合には非効率的です。インデックスを使用すると、MongoDB はクエリ条件に一致するドキュメントを効率的に見つけられるようになり、クエリのパフォーマンスが大幅に高速化されます。
カーソルベースのページネーションのコンテキストでは、インデックスにより、次のドキュメント セット (documentId に基づく) のフェッチが迅速になり、コレクションにドキュメントが追加されてもパフォーマンスが低下しないことが保証されます。
オフセットベースのページネーションは実装が簡単ですが、大規模なデータセットではレコードをスキャンする必要があるため非効率になる可能性があります。一方、カーソルベースのページネーションは、よりスケーラブルなソリューションを提供し、データセットのサイズに関係なくパフォーマンスの一貫性を保ちます。 MongoDB で大規模なコレクションを操作している場合、よりスムーズで高速なエクスペリエンスを実現するために、カーソルベースのページネーションを検討する価値があります。
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 < 2000000; i++) { bulkOps.push({ insertOne: { documentId: i, name: `Record-${i}`, value: Math.random() * 1000, }, }); // Execute every 10000 operations and reinitialize if (bulkOps.length === 10000) { await collection.bulkWrite(bulkOps); bulkOps = []; } } if (bulkOps.length > 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();
以上がMongoDB を解き放つ: カーソルベースのページネーションが常にオフセットベースのページネーションよりも優れている理由!の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。