MST

星途 面试题库

面试题:Node.js应用中处理高并发数据库查询的索引策略

在一个高并发的Node.js web应用中,使用MongoDB数据库。应用需要处理大量同时对订单表的查询请求,订单表中有订单编号、用户ID、订单金额、下单时间等字段。部分查询需要根据用户ID和下单时间范围获取订单,部分查询需要根据订单金额范围获取订单。请阐述如何设计索引以应对这种高并发场景,同时说明在Node.js中使用`mongoose`模块连接MongoDB时,如何在模型定义中设置索引以满足这些查询需求,并且如何避免索引争用等性能问题。
35.1万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

索引设计

  1. 复合索引用于按用户ID和下单时间范围查询:对于根据用户ID和下单时间范围获取订单的查询,应该创建一个复合索引。在MongoDB中,复合索引的顺序很重要,应将选择性高(区分度大)的字段放在前面。通常用户ID的区分度比下单时间范围大,所以索引顺序为 userID 在前,orderTime 在后。这样可以快速定位到特定用户的订单,然后再在这个子集里根据下单时间筛选。
    // 假设mongoose模型定义如下
    const mongoose = require('mongoose');
    const orderSchema = new mongoose.Schema({
        orderId: String,
        userId: String,
        orderAmount: Number,
        orderTime: Date
    });
    orderSchema.index({ userId: 1, orderTime: 1 });
    const Order = mongoose.model('Order', orderSchema);
    
  2. 单索引用于按订单金额范围查询:对于根据订单金额范围获取订单的查询,创建一个针对 orderAmount 的单索引即可。
    orderSchema.index({ orderAmount: 1 });
    

在mongoose模型定义中设置索引

  1. 复合索引设置:如上述代码,使用 index 方法在 Schema 上定义复合索引。index 方法接受一个对象,对象的键是字段名,值为1表示升序索引,-1表示降序索引。对于 userIdorderTime 的复合索引,代码为 orderSchema.index({ userId: 1, orderTime: 1 });
  2. 单索引设置:同样使用 index 方法定义单索引,例如针对 orderAmount 的单索引,代码为 orderSchema.index({ orderAmount: 1 });

避免索引争用等性能问题

  1. 合理规划索引数量:避免创建过多不必要的索引。每个索引都会占用额外的存储空间,并且在写入操作时会增加开销。只创建真正需要用于查询的索引。
  2. 读写分离:在高并发场景下,可以考虑使用读写分离策略。主节点处理写操作,从节点处理读操作。这样可以减轻主节点的压力,减少读写操作之间的争用。在Node.js中,可以通过配置 mongoose 连接字符串来指定主从节点。例如:
    const mongoose = require('mongoose');
    const uri ='mongodb://primary:27017,secondary1:27017,secondary2:27017/mydb?replicaSet=myReplicaSet&readPreference=secondaryPreferred';
    mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true });
    
  3. 索引维护:定期检查索引的使用情况,使用 db.collection.stats() 命令查看索引的使用频率等信息。对于长时间未使用的索引,可以考虑删除,以减少索引维护的开销。
  4. 批量操作:尽量使用批量操作代替单个操作。例如,在进行插入操作时,使用 insertMany 而不是多次 insertOne。这样可以减少数据库的交互次数,提高性能,同时也能减少索引争用的机会。