」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 釋放 MongoDB:為什麼基於遊標的分頁每次都優於基於偏移量的分頁!

釋放 MongoDB:為什麼基於遊標的分頁每次都優於基於偏移量的分頁!

發佈於2024-11-07
瀏覽:232

分页在处理大型数据集时是任何数据库操作的关键部分。它允许您将数据分割成可管理的块,从而更容易浏览、处理和显示。 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. 基于光标的分页

基于游标的分页,也称为键集分页,依赖于唯一标识符(例如 ID 或时间戳)来对记录进行分页。它不是跳过一定数量的记录,而是使用最后检索到的记录作为获取下一组记录的参考点。

这种方法效率更高,因为它避免了扫描当前页之前的记录。因此,无论您深入数据集多深,查询时间都保持一致。

以下是基于光标的分页代码:

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

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如有侵犯,請聯絡study_golang@163 .com刪除
最新教學 更多>
  • 逐步設定 React 和 Vite
    逐步設定 React 和 Vite
    Vite 是一款現代建立工具,旨在提供快速高效的開發體驗,特別是對於基於 JavaScript 的應用程序,例如 React、Vue 等。 Vite本身更注重開發速度,在開發過程中以最少的配置和更快的載入時間。由於匯總的最佳化,生產建置時間通常也更快 在本教學中,您將逐步學習如何使用 Vite 安...
    程式設計 發佈於2024-11-08
  • 如何在 JavaScript 中取得轉換後元素的準確寬度和高度?
    如何在 JavaScript 中取得轉換後元素的準確寬度和高度?
    在變換後檢索寬度和高度當對元素應用諸如旋轉(45deg)之類的變換時,該元素的視覺尺寸改變。但是,JavaScript 中的 width 和 height 屬性仍然反映原始未轉換的尺寸。 解決方案:使用 getBoundingClientRect()要取得轉換後更新的尺寸,請使用HTMLDOMEle...
    程式設計 發佈於2024-11-08
  • 使用 Python 抓取喬治亞州亞特蘭大律師資料的技術指南
    使用 Python 抓取喬治亞州亞特蘭大律師資料的技術指南
    在本指南中,我們將探討如何使用 Python 從法律網站上抓取律師數據,重點關注佐治亞州亞特蘭大的律師。這些資訊對於想要尋找律師、研究律師事務所或收集附近律師資料的人來說非常有價值。我們將使用流行的 Python 庫創建一個強大的抓取工具,可以幫助您收集亞特蘭大地區律師的資訊。 先決條件 在開始之...
    程式設計 發佈於2024-11-08
  • 掌握腳本標籤:使用 Async 和 Defer 進行精確的腳本控制
    掌握腳本標籤:使用 Async 和 Defer 進行精確的腳本控制
    在 Web 開發領域,優化頁面載入時間至關重要。 標籤的兩個強大屬性 - 非同步和延遲 - 可以顯著影響網站的效能。在沒有徹底理解這些屬性的情況下使用它們可能會影響效能並導致錯誤。讓我們從基礎開始,了解這些屬性的作用以及何時使用它們。 基礎知識:腳本如何加載 預設情況下,當瀏覽器...
    程式設計 發佈於2024-11-08
  • JavaScript 中 +=_ 運算子背後的奧秘是什麼?
    JavaScript 中 +=_ 運算子背後的奧秘是什麼?
    解碼JavaScript 中神秘的=_ 運算子JavaScript 中不常見的運算子=_ 讓開發人員感到困惑,讓他們想知道它的真正本質。此運算子結合了賦值運算子 = 和一元加運算子 _。讓我們深入研究它的複雜性並揭開它的用途。 一元加運算子 (_)一元加運算子 ( ) 是一個嘗試轉換其運算元的前綴運...
    程式設計 發佈於2024-11-08
  • CSS Flexbox:建立定價表
    CSS Flexbox:建立定價表
    介紹 CSS Flexbox 是 Web 開發人員創建靈活且響應式佈局的強大工具。 Flexbox 最常見的用例之一是建立定價表,這是許多網站的關鍵元素。在本文中,我們將討論使用 CSS Flexbox 建立定價表的優點和缺點,並探討其一些關鍵功能。 優點 將 C...
    程式設計 發佈於2024-11-08
  • 如何在 JavaScript 中格式化具有特定小數位的浮點數?
    如何在 JavaScript 中格式化具有特定小數位的浮點數?
    將浮點數格式化為特定小數位在JavaScript 中,從浮點數轉換為字串可能會導致尾隨小數位。若要限制小數點後的位數,您可以使用特定函數。 舍入函數一種方法是使用舍入函數,例如 toFixed。例如:var number = 0.3445434; console.log(number.toFixed...
    程式設計 發佈於2024-11-08
  • 為什麼我放棄 Python Flask 而選擇 Django:Web 框架對決
    為什麼我放棄 Python Flask 而選擇 Django:Web 框架對決
    當您開始使用 Python Web 開發時,您可能會遇到 Django 和 Python Flask 作為兩個最佳選擇。這兩個框架都有其優點,但根據我的經驗,Django 通常是更好的選擇。 我早期使用 Python Flask 的經歷 當我第一次開始探索 Web 開發時,Pyth...
    程式設計 發佈於2024-11-08
  • React原始碼中MessageChannel的使用
    React原始碼中MessageChannel的使用
    這篇文章我們分析React原始碼中MessageChannel的用法。 我們先來了解什麼是MessageChannel。 訊息頻道 Channel Messaging API 的 MessageChannel 介面允許我們建立一個新的訊息通道並透過它的兩個 MessagePort...
    程式設計 發佈於2024-11-08
  • 掌握 Java 單元測試:&#Student Class Test&# 項目
    掌握 Java 單元測試:&#Student Class Test&# 項目
    透過 LabEx 的學生類測試專案深入單元測試的世界,釋放您作為 Java 開發人員的潛力。這門綜合課程將引導您完成為簡單的 Student 類別編寫有效單元測試的過程,使您能夠編寫更可靠和可維護的程式碼。 介紹 在不斷發展的軟體開發領域,編寫健全且經過良好測試的程式碼的能力變得越...
    程式設計 發佈於2024-11-08
  • 如何在 JavaScript 中模擬屬性的 noSuchMethod 功能?
    如何在 JavaScript 中模擬屬性的 noSuchMethod 功能?
    如何在JavaScript 中實現noSuchMethod 屬性功能在JavaScript 中,noSuchMethod在JavaScript 中,noSuchMethod雖然標準 JavaScript 語言中的屬性沒有直接等效項,但可以模擬類似的屬性使用 ECMAScript 6 代理程式的功能。...
    程式設計 發佈於2024-11-08
  • 使用 GitLab CI/CD 和 Terraform 實作 Lambda 以進行 SFTP 整合、Go 中的 S Databricks
    使用 GitLab CI/CD 和 Terraform 實作 Lambda 以進行 SFTP 整合、Go 中的 S Databricks
    通过 Databricks 中的流程自动化降低成本 我的客户需要降低在 Databricks 上运行的流程的成本。 Databricks 负责的功能之一是从各种 SFTP 收集文件,解压缩它们并将它们放入数据湖中。 自动化数据工作流程是现代数据工程的重要组成部分。在本文中,我们将探...
    程式設計 發佈於2024-11-08
  • 為什麼我的 GoLang 網路伺服器無法提供大型 MP4 影片?
    為什麼我的 GoLang 網路伺服器無法提供大型 MP4 影片?
    GoLang HTTP Webserver Serving MP4 Video挑戰使用 GoLang 創建了一個提供 HTML/JS/CSS 和映像的 Web 伺服器。當伺服器嘗試提供 MP4 視訊檔案時,視訊載入失敗,僅顯示視訊控制。 調查檢查視訊檔案後,發現較小的視訊可以正常工作,而較大的視訊則...
    程式設計 發佈於2024-11-08
  • 如何在不使用 HTML 表單的情況下使用 PHP 重新導向網頁並傳送 POST 資料?
    如何在不使用 HTML 表單的情況下使用 PHP 重新導向網頁並傳送 POST 資料?
    使用PHP 重定向和發送POST 資料在這個問題中,我們遇到了一個獨特的挑戰:如何重定向網頁並透過POST 方法不依賴HTML 表單。期望的結果是使用 PHP 腳本將隱藏欄位提交到外部網關。通常,透過GET 傳送資料非常簡單,如下面的程式碼片段所示:header('Location: http://...
    程式設計 發佈於2024-11-08
  • 如何處理JSF表單提交過程中的授權失敗?
    如何處理JSF表單提交過程中的授權失敗?
    JSF 表單提交期間的授權失敗:綜合分析在JSF 應用程式中實現自訂授權機制時,了解頁面導航和表單提交之間的區別至關重要。雖然重定向可以無縫地進行頁面導航,但它們在表單提交期間可能會遇到問題。 問題原因此問題的根本原因在於 JSF 表單提交觸發非同步請求。當發送重定向作為對非同步請求的回應時,JSF...
    程式設計 發佈於2024-11-08

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3