MST

星途 面试题库

面试题:MongoDB部分索引:复杂场景优化

假设有一个电商系统,MongoDB中存储了大量的订单数据,文档结构包含{order_id: 'string', customer_id: 'string', order_date: 'date', order_status: 'string', products: [ { product_id: 'string', quantity: 'number' } ]}。现在需要根据不同的业务场景进行查询优化,如查询特定日期内完成订单且包含特定产品的订单,以及查询某个客户的最近10个订单。请设计合适的部分索引策略,并解释为何这样设计,同时分析在高并发读写场景下该索引策略可能面临的问题及解决思路。
47.5万 热度难度
数据库MongoDB

知识考点

AI 面试

面试题答案

一键面试

1. 查询特定日期内完成订单且包含特定产品的订单

  • 索引策略:创建复合部分索引,索引字段为 order_dateorder_statusproducts.product_id。假设完成订单状态为 completed,仅对 order_statuscompleted 的文档创建索引,示例代码如下(假设使用Node.js的MongoDB驱动):
const { MongoClient } = require('mongodb');

async function createIndex() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db('ecommerce');
    const orders = database.collection('orders');

    const indexKeys = {
      order_date: 1,
      order_status: 1,
      'products.product_id': 1
    };
    const indexOptions = {
      partialFilterExpression: {
        order_status: 'completed'
      }
    };

    await orders.createIndex(indexKeys, indexOptions);
  } finally {
    await client.close();
  }
}

createIndex().catch(console.error);
  • 设计原因
    • order_date 作为范围查询字段,放在索引开头可以快速定位到特定日期范围内的文档。
    • order_status 过滤条件固定为 completed,通过部分索引仅对符合该条件的文档创建索引,减少索引体积。
    • products.product_id 用于匹配特定产品,放在最后可以进一步缩小查询范围。

2. 查询某个客户的最近10个订单

  • 索引策略:创建复合部分索引,索引字段为 customer_idorder_date,按 order_date 降序排列,仅对 customer_id 不为空的文档创建索引,示例代码如下:
async function createIndex2() {
  const uri = "mongodb://localhost:27017";
  const client = new MongoClient(uri);

  try {
    await client.connect();
    const database = client.db('ecommerce');
    const orders = database.collection('orders');

    const indexKeys = {
      customer_id: 1,
      order_date: -1
    };
    const indexOptions = {
      partialFilterExpression: {
        customer_id: { $ne: null }
      }
    };

    await orders.createIndex(indexKeys, indexOptions);
  } finally {
    await client.close();
  }
}

createIndex2().catch(console.error);
  • 设计原因
    • customer_id 用于定位特定客户的文档,放在索引开头。
    • order_date 按降序排列,便于快速获取最近的订单,通过部分索引减少索引体积。

高并发读写场景下可能面临的问题及解决思路

  • 问题
    • 索引维护开销:高并发写操作时,索引需要频繁更新,导致性能下降。
    • 锁争用:读写操作可能会因为索引的更新而产生锁争用,影响系统并发性能。
  • 解决思路
    • 批量操作:将多个写操作合并为批量操作,减少索引更新次数。
    • 读写分离:采用读写分离架构,读操作从副本集读取数据,减少主节点的压力。
    • 优化索引结构:定期评估索引的使用情况,删除不必要的索引,减少索引维护开销。
    • 调整锁粒度:使用细粒度锁,减少锁争用范围,例如在MongoDB中使用文档级锁而非集合级锁。