在 Hapi 框架中遇到的 Mongoose 查询性能问题详解

在 Hapi 框架中遇到的 Mongoose 查询性能问题详解

在使用 Hapi 框架和 Mongoose 进行开发时,我们可能会遇到一些性能问题,尤其是在进行复杂查询时。这篇文章会分析其中的原因,并给出优化建议。

问题重现

在一个较复杂的项目中,我们使用了 Hapi 和 Mongoose 进行开发。其中,有一个需求需要进行多表查询,需要连接多个数据库表,并在其中筛选出符合条件的数据。我们最开始的实现如下(代码省略部分非关键代码):

----- ------ - ----- ------------- ---------- ---- -------------
  ----- ------------
  ------ - ----------- ---- --
  ------- -----
  --------- - ----- ------------------ ------- ---- --
-------------

这个查询逻辑并不复杂,但是在进行了一段时间后,我们发现查询时间非常长,而且当查询偏大时,查询效率更是堪忧。

我们想通过剖析代码确信没有什么明显的错误,并在不减少查询条件数量的情况下提高查询性能。

分析问题

在深入分析之前,我们想对 Mongoose 和数据库做一些简单介绍,以便更好地理解问题以及优化措施。

Mongoose

Mongoose 是一个优美的 Node.js MongoDB 模型驱动的对象模型,它使得在 Node.js 中处理 MongoDB 数据变得非常简单和顺畅。它不仅提供了简单而优雅的方式来执行 CRUD 操作,还提供轻松访问 MongoDB 数据库的多个功能。

相比于纯粹的 MongoDB 流行度,Mongoose 通常被选择为处理数据库时的 Node.js 首选。它将数据结构化成有意义的模型,并提供了从身份验证到查询优化的各种功能。

MongoDB

MongoDB 是一种基于分布式文件存储的数据库,由 C++ 编写。旨在为 Web 应用提供可扩展的高性能数据存储解决方案。

MongoDB 的重要特点包括:面向文档、模式自由、支持动态查询、支持完全索引、支持复制和故障恢复、使用高效的 BSON 存储数据。

既然你理解了 Mongoose 和 MongoDB,则很容易理解以下原则:

快速查询的关键在于在查询中使用索引。

问题原因

回到我们的查询逻辑,我们首先简单概述一下它的查询流程:

  1. 在使用 find 方法进行查询时,MongoDB 首先扫描索引,从符合条件的索引中获取文档 ID 数组。

  2. MongoDB 取得文档 ID 后,使用 _id 查询非索引字段或者其他值作为输入到下一阶段的过滤器。仅包含符合过滤器的文档。如果一个文档满足过滤器中的所有条件,则文档能够通过滤器。

  3. 将对象返回给用户进行处理。

根据上述过程,我们可以预想到程序的性能开销在 _id 查询的耗时上。

查询性能下降原因有多种,但是在这里,我们简单地总结一些:

  1. 对于非索引字段上的过滤器查询时的缺失。

  2. 当我们的数据量变大时,查询会变得昂贵。

  3. 由于 join 或者深度数据嵌套检索时,在非索引字段上进行大量过滤,从而降低了效率。

  4. 在查询期间,如果需要对文件进行排序,它很可能涉及大量内存活动。

解决方案

到这里,我们可以开始考虑优化解决方案了。

  1. 对于第一种原因,我们需要了解优化 SQL 查询的方式,并将其应用到 Mongoose 查询中。

    • 添加索引。请在查询字段上添加索引。
    • 请避免查询非索引字段。当您在非索引字段上过滤时,这极大地影响了查询速度。
    • 避免查询时显示所有数据。尽量使用 $project 限制返回字段。
  2. 对于第二种原因,我们可以使用另一个技巧来优化查询:

    • 使用 skip 和 limit。定位到您想要的数据,并在那里切断查询。例如,归档旧数据也可以是有效的优化方案。
    • 避免使用全集合扫描。如果您已经遍历了一个很长的集合,那么结果可能会很慢。此时,您可能需要使用更高级的聚合框架。
  3. 对于第三个原因,我们建议:

    • 使用 Native Lookup 来实现 join。

利用 $lookup,我们可以实现类似于 SQL JOIN 的操作。但是,在 Mongoose 中使用 $lookup 时,必须注意并避免使用非索引字段的 $match

----- ------ - ----- ------------------
  - ------- - ---------- ---- - --
  - -------- - ----- --------- ----------- ------ ------------- ------------ --- --- - --
  - -------- - ----- --------- ----------- ------ ------------- ------------ --- --- - --
  - --------- - ---------- -- -- - -------- - ------ ----- --- ---- ----- - ---- ----------------- ----- - - -- -- - -------- - ------ ----- --- ---- ----- - ---- ----------------- ----- - - - - --
  - ------- -- -
--

其中,我们使用多个 $lookup 进行 join,最后使用 $project$filter 对于各个表格字段进行过滤。最后再使用 limit 方法限制查询数量,从而进行优化。

  1. 最后,对于第四个原因,请使用 $sort$skip 来限制排序和跳过。

结论

在本文中,我们讨论了使用 Hapi 和 Mongoose 进行开发时可能遇到的问题:在进行多表查询时遇到了性能问题。最后,我们提供了四种优化解决方案,包括:

  1. 在查询上使用索引,避免在非索引字段上进行大量过滤。

  2. 使用 skip 和 limit 等策略限制查询数量。

  3. 使用 Native Lookup 来实现 join,并使用 $project$filter 对于各个表格字段进行过滤。

  4. 使用 $sort$skip 来限制排序和跳过。

为了使您的 Mongoose 应用程序性能更佳,您需要遵循最佳实践并不断调整您的应用程序。同时,我们也应该不断学习、思考。希望通过本文的分析和介绍,能够让大家了解和优化 Mongoose 查询的性能问题,并提升我们的开发能力和效率。

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/64a4dd0948841e9894144ff6


猜你喜欢

  • 解读 ECMAScript 2020 的块级作用域

    在 ECMAScript 2020 规范中,块级作用域(Block-scoped declarations)得到了强化和拓展,从而使得编写 JS 代码变得更加方便和高效。

    1 年前
  • 使用 Sequelize 处理日期类型数据的技巧

    在 Web 开发中,经常会涉及到日期类型数据的处理。Sequelize 是一个 Node.js 中的 ORM 框架,可以帮助我们在后端应用中处理数据库操作。本文将介绍使用 Sequelize 处理日期...

    1 年前
  • Promise.allSettled() 的使用及注意事项

    Promise.allSettled() 是一个ES2020新增的Promise方法,它可以在所有Promise都已经fulfilled或rejected后返回一个数组,该数组包含每个Promise的...

    1 年前
  • 回归 Mongoose:重新定义数据模型设计

    前言 在前端开发过程中,数据库是一个不可或缺的环节。为了更好地设计数据库,使得数据存储可靠、方便管理,需要使用熟悉的数据库框架。近年来,Mongoose 作为一种 Node.js 与 MongoDB ...

    1 年前
  • Fastify 中如何实现静态文件的访问和下载?

    在现代的 Web 应用中,静态文件(如 HTML、CSS、JavaScript 和图像)的发布和管理是非常重要的,因为这些文件是用户在浏览器中渲染页面所必需的组成部分。

    1 年前
  • Redis 集群扩容和缩容的正确姿势

    随着互联网发展,对于数据库的高可用性、高性能、高扩展性等需求也越来越高,而 Redis 作为一个高可用、高性能的 NoSQL 数据库,在这方面表现非常出色。但是,在使用 Redis 集群时,我们需要时...

    1 年前
  • ES6 中的 Symbol 对象与枚举类型的实现

    ES6 中的 Symbol 对象与枚举类型的实现 在 JavaScript 的 ES6 版本中,新增了一种原始数据类型:Symbol。Symbol 是一种不可变且唯一的数据类型,主要用于对象属性名的定...

    1 年前
  • 使用 Flexbox 实现响应式图片列表布局

    在这个移动设备和桌面显示器并存的时代,设计难度增加了,需要考虑到不同设备的显示效果。Flexbox 是一种布局模式,可使响应式设计变得十分容易。本文将介绍怎样使用 Flexbox 实现响应式图片列表布...

    1 年前
  • 如何在 Cypress 中使用自定义的配置文件

    如何在 Cypress 中使用自定义的配置文件 Cypress 是一个非常流行的前端自动化测试框架,它的使用非常简单,但有时候需要对一些配置进行修改,如测试用例所在的路径,测试超时时间等等。

    1 年前
  • Koa-router 中跨域请求的解决方案

    前端开发过程中,经常需要向不同的服务器发送请求,这就涉及到跨域问题。在 Koa 框架中,我们可以使用 koa-router 来进行路由的管理和控制,但是默认情况下,koa-router 并没有提供处理...

    1 年前
  • Vue.js 中如何集成第三方组件库

    Vue.js 是一款非常流行的前端框架,它的生态环境非常丰富。在实际的项目开发中,我们经常会用到一些第三方组件库,比如 Element UI、Ant Design Vue 等。

    1 年前
  • Web 性能优化之减少 HTTP 请求的方法探究

    在 Web 前端开发中,HTTP 请求对页面加载速度和性能影响非常明显。为了提升 Web 应用的性能和用户体验,我们需要尽可能减少 HTTP 请求的次数。本文将深入探究减少 HTTP 请求的方法,探讨...

    1 年前
  • Headless CMS 在构建智能化门户网站的作用

    前言 Headless CMS 是一种新的 CMS 架构方式,其特点是将前端与后台做了解耦,前端的 UI 层可以自行组织数据,而不再依赖后台服务。中文翻译为无头 CMS,是指没有直接管理前端显示的功能...

    1 年前
  • 使用 Server-sent Events 实现带实时搜索的城市天气查询

    在当今互联网时代,实时搜索和实时数据展示已经成为了非常常见的需求。这些实时数据很多时候都是需要通过异步更新的方式展示出来,而在前端开发过程中,Server-sent Events (SSE) 就是一种...

    1 年前
  • ES8 中新增的 for-await-of 循环语句详解

    随着 JavaScript 的飞速发展,越来越多的新语言特性被加入其中,最近 ES8 中新增了一个 for-await-of 循环语句,让我们一起来看看这个新特性的详细信息和学习指导。

    1 年前
  • Enzyme 测试 Redux 的 React 组件方法

    Enzyme 是一个流行的 React 测试工具,它提供了一种简单而强大的方式来测试 React 组件。当我们需要测试 Redux 和 React 组件的结合时,Enzyme 成为了有力的助手。

    1 年前
  • Angular使用RxJS+WebSocket长连接实现消息推送

    随着前端技术的不断变化和发展,Web应用也越来越复杂,接收实时消息推送的需求越来越普遍,因此实现消息推送成为了前端开发中的一个重要而且切实可行的问题。本文将介绍如何使用RxJS和WebSocket技术...

    1 年前
  • Socket.io 实现多人在线游戏开发中的应用

    Socket.io 是一个能够实现实时双向通信的库,其具备可靠性、速度和简易性等优点。在多人在线游戏开发中,往往需要通过 Socket.io 来实现多个用户之间的实时通信,来使游戏更加流畅且真实。

    1 年前
  • MongoDB 聚合查询数据类型转换的详解

    MongoDB 是一个非关系型数据库,在前端开发中广泛使用。MongoDB 中提供了聚合查询的功能,可以对多个文档进行数据处理和转换。在聚合查询中,进行数据类型转换是非常重要的一个环节,本文将对 Mo...

    1 年前
  • 无障碍性技术应用于智慧公交的设计研究

    1.前言 智慧公交是现代公共交通领域的重要一环。智慧公交综合运用现代信息技术和先进的公共交通管理模式,为用户提供更加便捷、舒适的出行环境。然而,在智慧公交的设计中,无障碍性技术的应用却受到了较少的关注...

    1 年前

相关推荐

    暂无文章